Ответ
Паттерн Decorator (Декоратор) — это структурный шаблон, позволяющий динамически добавлять объектам новое поведение, оборачивая их в объекты-обёртки. Это более гибкая альтернатива наследованию для расширения функциональности.
Ключевая идея: Декоратор реализует тот же интерфейс, что и исходный объект, и содержит ссылку на него. Это позволяет строить цепочки декораторов.
Пример на PHP (кофе с добавками):
// Базовый интерфейс
interface Coffee {
public function getCost(): float;
public function getDescription(): string;
}
// Конкретный компонент
class SimpleCoffee implements Coffee {
public function getCost(): float {
return 50.0;
}
public function getDescription(): string {
return "Simple coffee";
}
}
// Базовый декоратор
abstract class CoffeeDecorator implements Coffee {
protected Coffee $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
public function getCost(): float {
return $this->coffee->getCost();
}
public function getDescription(): string {
return $this->coffee->getDescription();
}
}
// Конкретные декораторы
class MilkDecorator extends CoffeeDecorator {
public function getCost(): float {
return parent::getCost() + 20.0;
}
public function getDescription(): string {
return parent::getDescription() . ", milk";
}
}
class WhipDecorator extends CoffeeDecorator {
public function getCost(): float {
return parent::getCost() + 30.0;
}
public function getDescription(): string {
return parent::getDescription() . ", whip";
}
}
// Использование
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " costs " . $coffee->getCost() . "n";
// Simple coffee costs 50
$coffee = new MilkDecorator($coffee);
echo $coffee->getDescription() . " costs " . $coffee->getCost() . "n";
// Simple coffee, milk costs 70
$coffee = new WhipDecorator($coffee);
echo $coffee->getDescription() . " costs " . $coffee->getCost() . "n";
// Simple coffee, milk, whip costs 100
Преимущества:
- Гибкость: Поведение можно добавлять и комбинировать во время выполнения.
- Соответствует принципу открытости/закрытости: Классы компонентов закрыты для модификации, но открыты для расширения.
- Избегает сложных иерархий подклассов.
Недостатки:
- Может создать много маленьких классов.
- Цепочки декораторов иногда сложно конфигурировать и отлаживать.