Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct use of a decorator

I have a Products class. Now I want to add some kind of discount module to my site which should interact with the Products class.

Currently the only solution I can think of is using some kind of decorator pattern to wrap around the product class so it can alter the price of the product.

Like this:

class Product {
    function price() {
        return 10;
    }
}

class ProductDiscountDecorator {
    private $product;

    function __construct($product) {
        $this->product = $product;
    }

    function price() {
        return $this->product->price()*0.8;
    }
}

$product = new ProductDiscountDecorator(new Product());
echo $product->price();

This being the discount, the prices should be adjusted on every page on the website. So every page using the Product class should also add the decorator. The only way I could think of solving this is using a factory that automatically adds this decorator.

$product = $factory->get('product'); // returns new ProductDiscountDecorator(new Product());

It would probably work, but I feel like I'm misusing the decorator pattern here.

Do you guys have any thoughts on this? How would you implement something like this?

like image 460
acidtv Avatar asked Nov 04 '22 12:11

acidtv


1 Answers

A Decorator is one option. Another option would be to use a Strategy Pattern for calculating the discount

Example

class Product
{
    protected $discountStrategy;
    protected $price;

    public function __construct(DiscountStrategy $discountStrategy)
    {
        $this->discountStrategy = $discountStrategy;
    }

    public function getPrice()
    {
        return $this->discountStrategy->applyDiscount($this->price);
    }
}

and then capsule the various possible discounts into classes of their own:

interface DiscountStrategy 
{
    public function applyDiscount($cent);
}

class NoDiscount implements DiscountStrategy
{
    public function applyDiscount($cent)
    {
        return $cent;
    }
}

class PremiumDiscount implements DiscountStrategy
{
    public function applyDiscount($cent)
    {
        return $cent - $cent * 0.8;
    }
}

You'd still use a Factory to assemble the products but Strategies are more fine grained and you can reuse them in other situations as well, for instance, some loyal customers could get a Discount as well, even when the product itself doesnt have a discount attached.

like image 98
Gordon Avatar answered Nov 15 '22 00:11

Gordon