Декоратор
Аналогія
Допустимо, у вас свій автосервіс, що надає різні послуги. Як виставляти клієнтам рахунок? Додавати послідовно послуги та їх вартість - і врешті-решт вийде підсумкова сума до оплати. Тут кожен тип послуги це «декоратор».
Стисло
Шаблон «Декоратор» дозволяє динамічно змінювати поведінку об'єкта під час виконання, обгортаючи його в об'єкт класу «декоратора».
Вікіпедія
Шаблон «Декоратор» дозволяє підключати до об'єкта додаткову поведінку (статично чи динамічно), не впливаючи на поведінку інших об'єктів того ж класу. Шаблон часто використовується для дотримання принципу єдиного обов'язку (Single Responsibility Principle), оскільки дозволяє розділити функціональність між класами для вирішення конкретних завдань.
Приклад
Візьмемо як приклад кави. Спочатку просто реалізуємо інтерфейс:
interface Coffee
{
public function getCost();
public function getDescription();
}
class SimpleCoffee implements Coffee
{
public function getCost()
{
return 10;
}
public function getDescription()
{
return 'Simple coffee';
}
}
Можна зробити код, що розширюється, щоб при необхідності вносити модифікації. Додамо «декоратори»:
class MilkCoffee implements Coffee
{
protected $coffee;
public function __construct(Coffee $coffee)
{
$this->coffee = $coffee;
}
public function getCost()
{
return $this->coffee->getCost() + 2;
}
public function getDescription()
{
return $this->coffee->getDescription() . ', milk';
}
}
class WhipCoffee implements Coffee
{
protected $coffee;
public function __construct(Coffee $coffee)
{
$this->coffee = $coffee;
}
public function getCost()
{
return $this->coffee->getCost() + 5;
}
public function getDescription()
{
return $this->coffee->getDescription() . ', whip';
}
}
class VanillaCoffee implements Coffee
{
protected $coffee;
public function __construct(Coffee $coffee)
{
$this->coffee = $coffee;
}
public function getCost()
{
return $this->coffee->getCost() + 3;
}
public function getDescription()
{
return $this->coffee->getDescription() . ', vanilla';
}
}
Тепер приготуємо каву:
$someCoffee = новий SimpleCoffee();
echo $someCoffee->getCost(); // 10
echo $someCoffee->getDescription(); // Simple Coffee
$ someCoffee = New MilkCoffee ($ someCoffee);
echo $someCoffee->getCost(); // 12
echo $someCoffee->getDescription(); // Simple Coffee, milk
$ someCoffee = новий WhipCoffee ($ someCoffee);
echo $someCoffee->getCost(); // 17
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip
$ someCoffee = новий VanillaCoffee ($ someCoffee);
echo $someCoffee->getCost(); // 20
echo $someCoffee->getDescription(); // Simple Coffee, milk, whip, vanilla