Декоратор (Decorator)

Decorator (Декоратор) относиться к классу структурных паттернов. Он используется для динамического расширения функциональности объекта. Является гибкой альтернативой наследованию.
Сущность работы паттерна декоратор заключается в «оборачивании» готового объекта новым функционалом, при этом весь оригинальный интерфейс объекта остается доступным (декоратор переадресует все запросы объекту). Смысл заключается в том, чтобы можно было безболезненно комбинировать различные декораторы в произвольном порядке, навешивая их на различные объекты. В некотором роде, это похоже на технологию traits, за исключением того, что декораторы динамически навешиваются на объект, а traits статически на класс.
Структурно паттерн представляет собой такую схему:

Как видно из схемы, и конкретный объект и декоратор имеют общий родительский класс, это сделано для того, чтобы публичный интерфейс у этих объектов совпадал. В классе decorator все методы перегружаются, и заменяются на делегирование компоненту. В конкретных реализациях декоратора, необходимые методы дополняются функционалом. Тем самым у нас получается наследование без наследования. При такой структуре нам не важно является ли компонент декоратором или конкретной реализацией, потому как интерфейс у них совпадает, и, как результат, мы можем делать цепочки декораторов.
На PHP данный паттерн можно представить следующим образом:
[php]
abstract class Component
{
abstract public function Operation();
}
class ConcreteComponent extends Component
{
public function Operation()
{
return ‘I am component’;
}
}
abstract class Decorator extends Component
{
protected
$_component = null;
public function __construct(Component $component)
{
$this -> _component = $component;
}
protected function getComponent()
{
return $this -> _component;
}
public function Operation()
{
return $this -> getComponent() -> Operation();
}
}
class ConcreteDecoratorA extends Decorator
{
public function Operation()
{
return ‘<a>’ . parent::Operation() . ‘</a>’;
}
}
class ConcreteDecoratorB extends Decorator
{
public function Operation()
{
return ‘<strong>’ . parent::Operation() . ‘</strong>’;
}
}
// Example
$Element = new ConcreteComponent();
$ExtendedElement = new ConcreteDecoratorA($Element);
$SuperExtendedElement = new ConcreteDecoratorB($ExtendedElement);
print $SuperExtendedElement -> Operation(); // <strong><a>I am component</a></strong>
[/php]
В некоторых случаях, вместо переопределения всех методов используется магический метод __call

Результат

  • Большая гибкость
  • Легкие классы на верхних уровнях абстракции
  • Множество мелких объектов

В некоторых случаях, декоратор и конкретный компонент не наследуют один и тот же класс. В нашем примере к слову, это было излишним. Полное соответствие интерфейса также не всегда требуется (в таком случае декоратор выступает в роли адаптера).

Материал взят с источника

Leave a Reply