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

Назначение

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

Применимость

Используйте паттерн декоратор для:

  • для динамического, прозрачного для клиентов добавления обязанностей объектам;
  • для реализации обязанностей, которые могут быть сняты с объекта;
  • когда расширение путем порождения подклассов по каким-то причинам неудобно или невозможно. Иногда приходится реализовывать много независимых расширений, так что порождение подклассов для поддержки всех возможных комбинаций приведет к комбинаторному росту их числа. В других случаях определение класса может быть скрыто или почему-либо еще недоступно, так что породить от него подкласс нельзя.

Результаты

Плюсы

  • большая гибкость, нежели у статического наследования. Паттерн декоратор позволяет более гибко добавлять объекту новые обязанности, чем было бы возможно в случае статического (множественного) наследования. Декоратор может добавлять и удалять обязанности во время выполнения программы. При использовании же наследования требуется создавать новый класс для каждой дополнительной обязанности, что ведет к увеличению числа классов и, как следствие, к возрастанию сложности системы. Кроме того, применение нескольких декораторов к одному компоненту позволяет произвольным образом сочетать обязанности. Декораторы позволяют легко добавить одно и то же свойство дважды;
  • позволяет избежать перегруженных функциями классов на верхних уровнях иерархии. Декоратор разрешает добавлять новые обязанности по мере необходимости. Вместо того чтобы пытаться поддержать все мыслимые возможности в одном сложном, допускающем разностороннюю настройку в классе, вы можете определить простой класс и постепенно наращивать его функциональность с помощью декораторов. В результате приложение уже не платит за неиспользуемые функции. Нетрудно также определять новые виды декораторов независимо от классов, которые они расширяют, даже если первоначально такие расширения не планировались. При расширении же сложного класса обычно приходится вникать в детали, не имеющие отношения к добавляемой функциональности.

Минусы

  • декоратор и его компонент не идентичны. Декоратор действует как прозрачное обрамление. Но декорированный компонент все же не идентичен исходному. При использовании декораторов это следует иметь ввиду;
  • множество мелких объектов. При использовании в проекте паттерна декоратор нередко получается система, составленная из большого числа мелких объектов, которые похожи друг на друга и отличаются только способом взаимосвязи, а не классом и не значениями своих внутренних переменных. Хотя проектировщик, разбирающийся в устройстве такой системы, может легко настроить ее, но изучать и отлаживать ее очень тяжело.

Реализация

Применение паттерна декоратор требует рассмотрения нескольких вопросов:

  • соответствие интерфейсов. Интерфейс декоратора должен соответствовать интерфейсу декорируемого компонента;
  • отсутствие абстрактного класса декоратора. Нет необходимости определять абстрактный класс декоратора, если планируется добавить всего одну обязанность. Так часто происходит, когда вы работаете с уже существующей иерархией классов, а не проектируете новую;
  • облегченные классы компонентов. Чтобы можно было гарантировать соответствие интерфейсов, компонент и декоратор должны реализовывать один интерфейс;
  • изменение облика, а не внутреннего устройства объекта. Декоратор можно рассматривать, как появившуюся у объекта оболочку, которая изменяет его поведение. Альтернатива - изменение внутреннего устройства объекта, хорошим примером чего может служить паттерн Стратегия;

Структура

 

Участники

Component - компонент: определяет интерфейс для объектов, на которые могут быть динамически возложены дополнительные обязанности;

ConcreteComponent - конкретный компонент: определяет объект на который возлагаются дополнительные обязанности;

Decorator - декоратор: хранит ссылку на объект Component и определяет интерфейс, соответствующий интерфейсу Component;

ConcreteDecorator - конкретный декоратор: возлагает дополнительные обязанности на компонент.