Правильное использование декоратора - PullRequest
5 голосов
/ 26 октября 2011

У меня есть класс продуктов. Теперь я хочу добавить на свой сайт какой-нибудь модуль скидок, который должен взаимодействовать с классом 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 ]

2 голосов
/ 26 октября 2011

Декоратор является одним из вариантов. Другой вариант - использовать шаблон стратегии для расчета скидки

.

Пример

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

Вы бы все еще использовали Фабрику для сборки продуктов, но Стратегии более мелкозернистые, и вы можете использовать их и в других ситуациях, например, некоторые постоянные клиенты могут получить Скидку, даже если сам продукт не со скидкой.

0 голосов
/ 26 октября 2011

В целом выглядит неплохо.

Чтобы придерживаться хороших принципов проектирования ООП, я бы также определил интерфейс «Продукт»

есть.

interface IProduct { public function getPrice(); }

и внедрите его как в Product, так и в ProductDiscountDecorator

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