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

26. December 2009

    Это структурный шаблон проектирования, который применяется когда нужно добавить определенную функционально отдельному объекту, а не целому классу.

    Допустим у нас есть Объект который что-то делает с другим объектом. Например, сохраняет какой либо файл на диск, сериализует в xml и сохраняет.

    Проходит время, этот класс уже используем в 1000 мест в проекте.

    И тут понимаем, что нельзя хранить наши объекты просто сериазиованными, их могут открыть простым текстовым редактором и прочесть важную информацию! Не безопасно!Нам нужно добавить к классу Writer новую функциональность шифрования.

    Описание проблемы:
    Нужно изменить поведение объекта только в нескольких местах. В зависимости от ситуации может потребоваться несколько вариантов расширения поведения(возможны комбинации добавляемых  функций: шифрование и сжатие, шифрование и подпись ключом)

    Как это сделать? Менять сам класс, нельзя, т.к. мы хотим использовать так же и сохранение данные без шифрования. Можем сделать наследника от Writer и переопределить метод Write, чтоб тот предварительно все шифровал. Наследование, вроде подходит.. А представим, что нам нужно применять шифрование опционально, в зависимости от выбора пользователя добавлять шифрование, сжатие, подписывание ключом. Мы будем создавать наследников для всех этих случаев? И для их комбинаций тоже? Не очень красивое решение. В такой ситуации хорошо подходит использовать шаблон Декоратор.

  Decorator class diagram

    У нас в наличии всего четыре класса, каждый из которых предоставляет свою функциональность и содержит ссылку на другой компонент IWriter, благодаря которой мы можем комбинировать функциональности объектов в зависимости от ситуации.

 interface IWriter
{
    void Write(object Data);
}

public class Writer : IWriter
{
    public override void Write(object Data)
    {
        this.WriteInFile(Data);
    }
}

 

    Код класса CompressionWriterDecorator:

public CompressionWriterDecorator : IWriter
{
    IWriter innerComponent;

    public CompressionWriterDecorator(IWriter component)
    {
        innerComponent = component;
    }

    public override void Write(object Data)
    {
        object compressedObject= DoCompression(Data);

        innerComponent.Write(compressedObject);
    }
}



    Код класса CryptoWriterDecorator :

public CryptoWriterDecorator : IWriter
{
    IWriter innerComponent;

    public CryptoWriterDecorator (IWriter component)
    {
        innerComponent = component;
    }

    public override void Write(object Data)
    {
        object cryptedObject= DoCrypt(Data);

        innerComponent.Write(cryptedObject);
    }
}

 

    Допустим нам нужно только сжать объект и записать его на диск. Тогда мы делаем следующее:

new CompressionWriterDecorator( new Writer () ) . Write (DataObject) ;

 

    Или нам нужно только зашифровать и сохранить:

new CryptoWriterDecorator ( new Writer () ) . Write (DataObject) ;

 

    Или все вместе и зашифровать и сжать и сохранить:

new CryptoWriterDecorator ( new CompressionWriterDecorator( new Writer () ) ) . Write (DataObject) ;


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

    Имея всего 4е класса мы можем применять их возможности в произвольном порядке.

    Выдержка из GOF:
    Декоратор можно рассматривать как появившуюся у объекта оболочку, которая изменяет en, поведение. Альтернатива - изменение внутреннего устройства объекта, хорошим примером чего может служить паттерн стратегия. Стратегии лучше подходят в ситуациях, когда класс Component уже достаточно тяжел, так что применение паттерна декоратор обходится слишком дорого. В паттерне стратегия компоненты передают часть своей функциональности отдельному объекту-стратеги и, поэтому изменить или расширить поведение компонента допустимо, заменив этот объект.

    Родственнвенные типовые решения:

  •     Адаптер: если декоратор изменяет только обязанности объекта, но не его интерфейс, то адаптер придает объекту совершенно новый интерфейс.
  •     Компоновщик: декоратор можно считать вырожденным случаем составного бъекта, у которого есть только один компонент. Однако декоратор добавляет новые обязанности, агрегирование объектов не является его целью.
  •     Стратегия: декоратор позволяет изменить внешний облик объекта, стратегия - его внутреннее содержание. Это два взаимодополняющих способа изменения объекта.




Понятно написано в книге "Паттерны Проектирования" GOF:

http://ooad.asf.ru/Pattern.aspx?IdKat=7&IdPat=42 (прочитать обязательно)

Очень толково рассказано о шаблоне декоратор на RSDN
http://www.rsdn.ru/article/patterns/DecoratorPattern.xml

 

Architecture, Design Patterns ,

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading