Наследование паттерна декоратора

В шаблоне декоратора абстрактный класс реализует интерфейс, а конкретный класс (декоратор) расширяет абстрактный класс. Что произойдет с функциональностью шаблона, если конкретный класс напрямую реализует интерфейс вместо того, чтобы наследовать его через абстрактный класс?

2 ответа

Абстрактный класс не требуется. Со страницы 179 книги GoF,

Нет необходимости определять абстрактный класс Decorator, когда вам нужно добавить только одну ответственность. Это часто случается, когда вы имеете дело с существующей иерархией классов, а не разрабатываете новую. В этом случае вы можете объединить ответственность Decorator за пересылку запросов к компоненту в ConcreteDecorator.

Аналогичный вопрос от Head First Design: какова причина перемещения переменной экземпляра в абстрактный класс в шаблоне декоратора?

Оригинальная книга шаблонов проектирования (GoF) датируется 1994 годом и в качестве примеров использует C++ и SmallTalk. IIRC, C++ не имеет интерфейсов на уровне языка (по крайней мере, в 1994 году). Когда книга увещевает

Программа для интерфейса, а не реализация

вы должны интерпретировать слово interface как концепцию, а не языковую конструкцию.

В C++, например, обычно эмулируют интерфейсы с абстрактными классами, которые определяют исключительно чистые виртуальные функции. Многие примеры C++ в книге GoF делают это.

существует Между абстрактными классами и интерфейсамисильная связь , до такой степени, что они фактически взаимозаменяемы.

Что касается паттерна Decorator, я предполагаю, что всегда можно украсить интерфейс. Рассмотрим, например, такой интерфейс:

      public interface IFace
{
    void Command(Arg1 arg1, Arg2 arg2);
    Ret1 Query(Arg3);
}

AFAICT, вы всегда можете написать декоратор - по крайней мере, выродившийся декоратор:

      public class MyFace : IFace
{
    private readonly IFace inner;

    public MyFace(IFace inner)
    {
        this.inner = inner;
    }

    public void Command(Arg1 arg1, Arg2 arg2)
    {
        // Consider doing something interesting here...
        inner.Command(arg1, arg2);
        // ... or here
    }

    public Ret1 Query(Arg3)
    {
        // Consider doing something interesting here...
        Ret1 ret = inner.Query(arg3);
        // ... or here
        return ret;
    }
}

Таким образом, для шаблона Decorator не имеет значения, используете ли вы абстрактный класс или интерфейс.

Другие вопросы по тегам