Другое название: Wrapper (Обертка).

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

Задача. Иногда бывает нужно возложить дополнительные обязанности на отдельный объект, а не на класс в целом. Так, библиотека для построения графических интерфейсов пользователя должна уметь добавлять новое свойство, скажем, рамку или новое поведение (например, возможность прокрутки к любому элементу интерфейса).

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

Решение. Более гибким является другой подход: поместить компонент в другой объект, называемый декоратором, который как раз и добавляет рамку. Декоратор следует интерфейсу декорируемого объекта, поэтому его присутствие прозрачно для клиентов компонента. Декоратор переадресует запросы внутреннему компоненту, но может выполнять и дополнительные действия (например, рисовать рамку) до или после переадресации. Поскольку декораторы прозрачны, они могут вкладываться друг в друга, добавляя тем самым любое число новых обязанностей.

 

 

Предположим, что имеется объект класса TextView, который отображает текст в окне. По умолчанию TextView не имеет полос прокрутки, поскольку они не всегда нужны. Но при необходимости их удастся добавить с помощью декоратора ScrollDecorator. Допустим, что еще мы хотим добавить жирную сплошную рамку вокруг объекта TextView. Здесь может помочь декоратор BorderDecorator. Мы просто компонуем оба декоратора и получаем искомый результат.

На диаграмме объектов показано, как композиция объекта TextView с объектами BorderDecorator и ScrollDecorator порождает элемент для ввода текста, окруженный рамкой и снабженный полосой прокрутки.

 

 

Классы ScrollDecorator и BorderDecorator являются подклассами Decorator – абстрактного класса, который представляет визуальные компоненты, применяемые для оформления других визуальных компонентов.

VisualComponent – это абстрактный класс для представления визуальных объектов. В нем определен интерфейс для рисования и обработки событий. Отметим, что класс Decorator просто переадресует запросы на рисование своему компоненту, а его подклассы могут расширять эту операцию.

Подклассы Decorator могут добавлять любые операции для обеспечения необходимой функциональности. Так, операция ScrollTo объекта ScrollDecorator позволяет другим объектам выполнять прокрутку, если им известно о присутствии объекта ScrollDecorator. Важная особенность этого паттерна состоит в том, что декораторы могут употребляться везде, где возможно появление самого объекта VisualComponent. Поэтому клиент не может отличить декорированный объект от недекорированного, а значит, никоим образом не зависит от наличия или отсутствия оформлений.

Общая структура решения.

 

 

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

ConcreteComponent (TextView) – конкретный компонент: определяет объект, на который возлагаются дополнительные обязанности.

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

ConcreteDecorator (BorderDecorator, ScrollDecorator) – конкретные декораторы: реализуют дополнительные обязанности, возлагаемые на компонент.

Decorator переадресует запросы объекту Component. Также может выполнять и дополнительные операции до и после переадресации.

Применимость. Используйте паттерн Декоратор:

Результаты:

Особенности реализации. Применение паттерна Декоратор требует рассмотрения нескольких вопросов:

Родственные паттерны.

Адаптер: если Декоратор изменяет только обязанности объекта, но не его интерфейс, то адаптер придает объекту совершенно новый интерфейс.

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

Стратегия: Декоратор позволяет изменить внешний облик объекта, Стратегия – его внутреннее содержание. Это два взаимодополняющих способа изменения объекта.