/* */
НЕ МОЛЧИ!!!    Делай что-нибудь, чтобы остановить войну России в Украине.
Бойтесь равнодушных — они не убивают и не предают, но только с их молчаливого согласия существует на земле предательство и убийство.

Шаблон проектирования Декоратор

Описывается структурный шаблон проектирования Декоратор, приведены описание и пример реализации.

Шаблон проектирования Декоратор обычно применяют в случае, когда надо добавить новую функциональность в какой-то уже используемый компонент приложения. Обычно для расширения функций объекта практикуется создание наследников, но, как видите, есть и альтернатива. Подобный путь обычно себя оправдывает в случае, если к компоненту надо добавлять достаточно много небольших функций, что при наследовании приведет к разрастанию системы классов. Шаблон также удобен, когда требуются однотипные компоненты с небольшими различиями в поведении.
При реализации Декоратора, как и в случае с шаблоном Адаптер, вокруг изменяемого компонента создается обертка, с помощью которой и добавляются новые методы. Их можно добавлять как до выполнения кода изменяемого объекта, так и после. Разница между шаблонами в том, что интерфейс Адаптера отличается от изменяемого объекта, а интерфейс Декоратора совпадает с интерфейсом изменяемого объекта. Ну, вроде можно приступать к примеру реализации.

Удобно реализовать шаблон через абстрактные классы, это позволит в дальнейшем легко модифицировать приложение на базе абстракций. Смысл предыдущего утверждения будет понятен после пояснений кода. Итак, приступим.

//родитель компонента приложения, определяющий набор его базовых функций
abstract class AbstractComponent
{
    abstract public function operation();
    ...
}

//здесь реализуется набор базовых функций компонента приложения
class Component1 extends AbstractComponent
{
    public function operation() 
    {
        // ... реализация
    }
    
    // ... реализация других базовых функций компонента
}

//абстрактный класс, определяющий основной набор новых функций
abstract class AbstractDecorator extends AbstractComponent
{
    protected $component;
   
    public function __construct(AbstractComponent $component) 
    {
        $this->component = $component;
    }
    
    // ... реализация других основных новых функций компонента при необходимости
}

// набор1 новых функций компонента
class ComponentDecorator1 extends AbstractDecorator
{
    public function operation()
    {
        // ... расширенная функциональность, выполняемая до основных
        $this->component->operation();
        // ... расширенная функциональность, выполняемая после основных
    }
}

// набор2 новых функций компонента
class ComponentDecorator2 extends AbstractDecorator
{
    public function operation()
    {
        // ... расширенная функциональность, выполняемая до основных
        $this->component->operation();
        // ... расширенная функциональность, выполняемая после основных
    }
}

Надеюсь, все достаточно понятно из комментариев. Хочется только добавить следующее.
В классе AbstractComponent задаем функциональность нашего компонента.
В классе AbstractDecorator задается одна и больше новых функций изменяемого компонента. Кроме того, при создании экземпляра декоратора ему передается ссылка на исходный компонент, это позволяет его использование без изменений.
В классе  ComponentDecorator1 реализуется новое поведение изменяемого компонента.
В случае необходимости дальнейшей модификации функционала компонента мы легко это реализуем с помощью другого декоратора, создав, в частности, новый класс ComponentDecorator2.

Перейти к списку шаблонов проектирования.