Reputation: 3717
I am trying to use decorator pattern here. BaseCart is abstract class. Cart extends BaseCart and gets total price. Now I want to give discount on total cart value without changing the existing code. So I created CartDecorator which extends BaseCart and then created TotalDiscountCart which will get total amount and then apply discount on it.
Now I am trying to run unit test given below is not giving correct output. Product is added in cart but when Cart's getTotalPrice() method is called then productsWithQuantity is empty. Shouldn't it have values added? Why is it empty and how to solve it?
public abstract class BaseCart {
Map<Product, Integer> productsWithQuantity = new HashMap<Product, Integer>();
Double totalPrice = 0.0;
public void addProduct(Product product, Integer quantity){
productsWithQuantity.put(product, quantity);
}
public abstract Double getTotalPrice();
}
public class Cart extends BaseCart{
@Override
public Double getTotalPrice() {
productsWithQuantity.forEach((product ,quantity )-> totalPrice = totalPrice + product.getUnitPrice() * quantity);
return totalPrice;
}
}
public class CartDecorator extends BaseCart{
BaseCart cart;
public CartDecorator(BaseCart cart) {
super();
this.cart = cart;
}
@Override
public Double getTotalPrice() {
return this.cart.getTotalPrice();
}
}
public class TotalDiscountCart extends CartDecorator{
public TotalDiscountCart(BaseCart cart) {
super(cart);
}
@Override
public Double getTotalPrice() {
super.getTotalPrice();
return totalPrice - (percentDiscount(10.0));
}
private Double percentDiscount(Double i) {
return 0.1 * totalPrice;
}
}
@Test
public void shouldGiveDiscountOf9() {
//Given
BaseCart cart = new TotalDiscountCart(new Cart());
Product productDove = new Product("Dove soap", 30.0);
//when
cart.addProduct(productDove, 3);
// then
assertEquals(Double.valueOf(81.0),cart.getTotalPrice());
}
Upvotes: 0
Views: 124
Reputation: 43661
You should delegate addProduct
to cart
in CartDecorator
. It would also probably make sense to create a Cart
interface as CartDecorator
does not profit from subclassing BaseCart
.
Can you please elaborate this 'create a Cart interface as CartDecorator does not profit from subclassing BaseCart.'?
Your BaseCart
actually does two things. One is defining an interface to work with carts (consisting of addProduct
and getTotalPrice
methods). The other is provide a basic implementation for addProduct
which fills the productsWithQuantity
map.
Now a CartDecorator
decorates another cart. It (of course) should implement the same interface as all carts do. But for the CartDecorator
it is actually counterproductive to inherit the addProduct
implementation from the BaseCart
. Because CartDecorator
could delegate addProduct
to the decorated cart - so it actually does not need its own productsWithQuantity
map etc.
This is why it might make sense to define the Cart
interface and if you think you need it a basic abstract implementation like BaseCart
. The CartDecorator
then would implement the Cart
interface but not extend BaseCart
.
Upvotes: 1