PHP

Паттерн проектирования Декоратор (Decorator) на PHP

Перед прочтением ознакомьтесь с введением в паттерны проектирования на PHP, в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.

Decorator (Декоратор) относиться к классу структурных паттернов. Он используется для динамического расширения функциональности объекта. Является гибкой альтернативой наследованию.

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

Как видно из схемы, и конкретный объект и декоратор имеют общий родительский класс, это сделано для того, чтобы публичный интерфейс у этих объектов совпадал. В классе decorator все методы перегружаются, и заменяются на делегирование компоненту. В конкретных реализациях декоратора, необходимые методы дополняются функционалом. Тем самым у нас получается наследование без наследования. При такой структуре нам не важно является ли компонент декоратором или конкретной реализацией, потому как интерфейс у них совпадает, и, как результат, мы можем делать цепочки декораторов.

На 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>

В некоторых случаях, вместо переопределения всех методов используется магический метод __call

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

В некоторых случаях, декоратор и конкретный компонент не наследуют один и тот же класс. В нашем примере к слову, это было излишним. Полное соответствие интерфейса также не всегда требуется (в таком случае декоратор выступает в роли адаптера).
Теги:
decorator, design patterns, декоратор, паттерны проектирования
Добавлено: 27 Мая 2018 20:39:15 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...