Паттерн «Декоратор» (с примерами на C#, Java и PHP)

Паттерн «Декоратор» (Decorator) предназначен для добавления объекту нового функционала без порождения производных классов.

«Декоратор» имеет то же альтернативное англоязычное название, что и «Адаптер» — «Wrapper» (Обёртка). Но, между этими паттернами есть принципиальное отличие.

«Адаптер» преобразует интерфейс исходного класса к интерфейсу другого вида, который совместим с соответствующим окружением. В свою очередь «Декоратор» оставляет первоначальный интерфейс без изменений и расширяет функционал в его рамках.

Как это выглядит будет показано позже в примерах кода. Пока же рассмотрим составляющие паттерна.

Данная особенность также позволяет добавлять новые возможности для классов, для которых по тем или иным причинам создать наследников невозможно.

Паттерн «Декоратор» состоит из следующих компонентов:

  • Component (Компонент) – определяет интерфейс для объектов функционал которых может быть расширен при помощи декоратора;
  • ConcretteComponent (Конкретный компонент) – определяет сам объект функционал которого может быть расширен при помощи декоратора;
  • Decorator (Декоратор) – хранит ссылку на объект Component и определяет соответствующий ему интерфейс;
  • ConcreteDecorator (Конкретный декоратор) – непосредственно добавляет дополнительный функционал объекту Component.

Примеры реализации

Далее приведены примеры реализации паттерна «Декоратор» для трёх языков программирования: C#, Java и PHP.

C#

Component в нашем примере будет реализован в виде интерфейса.

interface IComponent
{
    void Operation();
}

В свою очередь ConcreteComponent будет уже в виде класса, реализующего этот интерфейс.

class ConcreteComponent : IComponent
{
    public void Operation()
    {
        Console.WriteLine("Operation");
    }
}

Decorator реализуем в виде абстрактного класса.

abstract class Decorator
{
    protected IComponent _component;
    public Decorator(IComponent component)
    {
        _component = component;
    }
    public abstract void Operation();
}

Также добавим в наш пример два конкретных декоратора:

class ConcreteDecoratorA : Decorator
{
    public ConcreteDecoratorA(IComponent component) : base(component) { }
    public override void Operation()
    {
        _component.Operation();
        Console.WriteLine(10 + 2);
    }
}
class ConcreteDecoratorB : Decorator
{
    public ConcreteDecoratorB(IComponent component) : base(component) { }
    public override void Operation()
    {
        _component.Operation();
        Console.WriteLine("Concrete decorator B");
    }
}

Обратите внимание. Расширение функционала осуществляется именно в конкретных декораторах в методах Operation путём вызова «родного» метода Operation объекта IComponent и последующего выполнения дополнительных операций уже в самих декораторах.

Теперь покажем работу всех компонентов паттерна «Декоратор» вместе.

IComponent component = new ConcreteComponent();
component.Operation();
// Первый декоратор.
Decorator decoratorA = new ConcreteDecoratorA(component);
decoratorA.Operation();
// Второй декоратор.
Decorator decoratorB = new ConcreteDecoratorB(component);
decoratorB.Operation();

Java

Составим аналогичную программу для Java.

Компонент:

public interface Component {
    void Operation();
}

Конкретный компонент:

public class ConcreteComponent implements Component {
    @Override
    public void Operation() {
        System.out.println("Operation");
    }
}

Декоратор:

public abstract class Decorator {
    protected Component component;
    public Decorator(Component component) {
        this.component = component;
    }
    public abstract void Operation();
}

Конкретные декораторы:

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    @Override
    public void Operation() {
        component.Operation();
        System.out.println("Concrete decorator A");
    }
}
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }
    @Override
    public void Operation() {
        component.Operation();
        System.out.println("Concrete decorator B");
    }
}

Всё вместе:

Component component = new ConcreteComponent();
component.Operation();
Decorator decoratorA=new ConcreteDecoratorA(component);
decoratorA.Operation();
Decorator decoratorB=new ConcreteDecoratorB(component);
decoratorB.Operation();

PHP

И в завершение пример на PHP (пример написан на PHP 7).

Компонент:

interface IComponent
{
    public function operation();
}

Конкретный компонент:

class ConcreteComponent implements IComponent
{
    public function operation()
    {
        echo "Operation";
    }
}

Декоратор:

abstract class Decorator
{
    protected $component;
    public function __construct(IComponent $component)
    {
        $this->component=$component;
    }
    public abstract function operation();
}

Конкретные декораторы:

class ConcreteDecoratorA extends Decorator
{
    public function __construct(IComponent $component)
    {
        parent::__construct($component);
    }
    public function operation()
    {
        $this->component->operation();
        echo 'Concrete decorator A';
    }
}
class ConcreteDecoratorB extends Decorator
{
    public function __construct(IComponent $component)
    {
        parent::__construct($component);
    }
    public function operation()
    {
        $this->component->operation();
        echo 'Concrete decorator B';
    }
}

Всё вместе:

<p>
    <?php
        $component = new ConcreteComponent();
        $component->operation();?><br />
    <?php
        $decoratorA = new ConcreteDecoratorA($component);
        $decoratorA->operation();?><br />
    <?php
        $decoratorB = new ConcreteDecoratorB($component);
        $decoratorB->operation();?><br />
</p>

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *