Шаблон оформления декоратора
Намерение
- Добавляйте дополнительные обязанности к объекту динамически. Декораторы предоставляют гибкую альтернативу подклассам для расширения функциональности.
- Указанное клиентом украшение основного объекта путем его рекурсивного обертывания.
- Упаковка подарка в коробку и упаковка в коробку.
Проблема
Вы хотите добавить поведение или состояние к отдельным объектам во время выполнения. Наследование невозможно, поскольку оно статично и применяется ко всему классу.
Обсуждение
Предположим, вы работаете над набором инструментов пользовательского интерфейса и хотите поддерживать добавление границ и полос прокрутки в окна. Вы можете определить иерархию наследования, например …
Но шаблон Decorator предлагает дать клиенту возможность указать любую комбинацию «функций», которую он желает.
Виджет * aWidget = new BorderDecorator ( новый HorizontalScrollBarDecorator ( новый VerticalScrollBarDecorator ( новое окно ( 80 , 24 ) ) ) ) ; aWidget -> draw ( ) ;
Этой гибкости можно достичь с помощью следующего дизайна
Другой пример каскадного (или сцепления) функций вместе для создания настраиваемого объекта может выглядеть так …
Stream * aStream = новый CompressingStream ( новый ASCII7Stream ( новый FileStream ( "fileName.dat" ) ) ) ; aStream -> putString ( "Привет, мир" ) ;
Решение этого класса проблем включает инкапсуляцию исходного объекта внутри абстрактного интерфейса оболочки. И объекты декоратора, и основной объект наследуются от этого абстрактного интерфейса. Интерфейс использует рекурсивную композицию, позволяющую добавлять неограниченное количество «слоев» декораторов к каждому базовому объекту.
Обратите внимание, что этот шаблон позволяет добавлять обязанности к объекту, а не методы к интерфейсу объекта. Интерфейс, представленный клиенту, должен оставаться постоянным при указании последовательных уровней.
Также обратите внимание, что идентичность основного объекта теперь «спрятана» внутри объекта декоратора. Попытка получить прямой доступ к основному объекту теперь является проблемой.
Состав
Клиент всегда заинтересован CoreFunctionality.doThis()
. Клиент может, или не может, быть заинтересованы в OptionalOne.doThis()
и OptionalTwo.doThis()
. Каждый из этих классов всегда делегирует базовый класс Decorator, и этот класс всегда делегирует содержащийся объект “wrappee”.
пример
Декоратор динамически прикрепляет к объекту дополнительные обязанности. Орнаменты, которые добавляют на сосны или ели, являются примерами декораторов. К дереву можно добавить огоньки, гирлянды, леденцы, стеклянные украшения и т. Д., Чтобы придать ему праздничный вид. Орнаменты не меняют саму елку, которая распознается как рождественская елка, независимо от того, какие украшения используются. В качестве примера дополнительной функциональности добавление лампочек позволяет «зажечь» елку.
Другой пример: штурмовое орудие само по себе является смертельным оружием. Но вы можете применить определенные «украшения», чтобы сделать его более точным, бесшумным и разрушительным.
Контрольный список
- Убедитесь, что контекст: один основной (или необязательный) компонент, несколько дополнительных украшений или оберток и общий для всех интерфейс.
- Создайте интерфейс «Наименьший общий знаменатель», который сделает все классы взаимозаменяемыми.
- Создайте базовый класс второго уровня (Decorator) для поддержки дополнительных классов-оболочек.
- Класс Core и класс Decorator наследуются от интерфейса LCD.
- Класс Decorator объявляет отношение композиции к интерфейсу LCD, и этот член данных инициализируется в его конструкторе.
- Класс Decorator делегирует объекту LCD.
- Определите производный класс Decorator для каждого дополнительного украшения.
- Производные классы Decorator реализуют свои функции оболочки и делегируют базовый класс Decorator.
- Клиент настраивает тип и порядок объектов Core и Decorator.
Эмпирические правила
- Адаптер предоставляет другой интерфейс для своей темы. Прокси-сервер предоставляет тот же интерфейс. Decorator предоставляет улучшенный интерфейс.
- Адаптер изменяет интерфейс объекта, декоратор расширяет обязанности объекта. Таким образом, декоратор более прозрачен для клиента. Как следствие, Decorator поддерживает рекурсивную композицию, что невозможно с чистыми адаптерами.
- Composite и Decorator имеют похожие структурные схемы, что отражает тот факт, что оба используют рекурсивную композицию для организации неограниченного числа объектов.
- Декоратор можно рассматривать как вырожденный композит только с одним компонентом. Однако декоратор добавляет дополнительные обязанности – он не предназначен для агрегирования объектов.
- Декоратор разработан, чтобы вы могли добавлять обязанности к объектам без создания подклассов. Composite фокусируется не на украшении, а на представлении. Эти намерения различны, но дополняют друг друга. Следовательно, Composite и Decorator часто используются вместе.
- Composite может использовать Chain of Responsibility, чтобы позволить компонентам получать доступ к глобальным свойствам через их родительский элемент. Он также может использовать Decorator для переопределения этих свойств в частях композиции.
- Декоратор и Прокси имеют разные цели, но похожую структуру. Оба описывают, как обеспечить уровень косвенного обращения к другому объекту, а реализации сохраняют ссылку на объект, которому они направляют запросы.
- Декоратор позволяет вам изменить скин объекта. Стратегия позволяет изменить кишки.