正确使用装饰器

aci*_*dtv 5 php design-patterns decorator

我有一个产品类.现在我想在我的网站上添加一些折扣模块,它应该与Products类进行交互.

目前我能想到的唯一解决方案是使用某种装饰模式来包装产品类,这样就可以改变产品的价格.

像这样:

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();
Run Code Online (Sandbox Code Playgroud)

这是折扣,价格应该在网站的每个页面上调整.所以每个使用Product类的页面都应该添加装饰器.我能想到解决这个问题的唯一方法是使用一个自动添加这个装饰器的工厂.

$product = $factory->get('product'); // returns new ProductDiscountDecorator(new Product());
Run Code Online (Sandbox Code Playgroud)

它可能会工作,但我觉得我在这里滥用装饰模式.

你们对此有什么想法吗?你会如何实现这样的东西?

Gor*_*don 2

装饰器是一种选择。另一种选择是使用策略模式来计算折扣

例子

class Product
{
    protected $discountStrategy;
    protected $price;

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

    public function getPrice()
    {
        return $this->discountStrategy->applyDiscount($this->price);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将各种可能的折扣封装到自己的类别中:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您仍然可以使用工厂来组装产品,但策略更加细粒度,您也可以在其他情况下重用它们,例如,一些忠实的客户也可以获得折扣,即使产品本身没有折扣随附的。