user1298426
user1298426

Reputation: 3717

Issue with Decorator design pattern in java

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

Answers (1)

lexicore
lexicore

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

Related Questions