正确使用装饰器

时间:2011-10-26 13:17:59

标签: 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();

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

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

它可能会起作用,但我觉得我在这里滥用了装饰模式。

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

2 个答案:

答案 0 :(得分:2)

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

实施例

class Product
{
    protected $discountStrategy;
    protected $price;

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

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

然后将各种可能的折扣包含在他们自己的课程中:

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;
    }
}

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

答案 1 :(得分:0)

一切看起来都很不错。

为了遵守良好的OOP设计原则,我还要定义一个“产品”界面

即。

interface IProduct { public function getPrice(); }

并在Product和ProductDiscountDecorator上实现它

class Product implements IProduct { ... }
class ProductDiscountDecorator implements IProduct { ... }