Сегодняшний шаблон — это шаблон Decorator, который позволяет динамически расширять поведение класса во время выполнения.
Декоратор в реальном мире
Концепция декоратора заключается в том, что он динамически добавляет дополнительные атрибуты к объекту. Реальным примером этого может быть рамка для фотографий. Картинка — это наш объект, который имеет свои особенности. Для демонстрации мы добавляем рамку к картине, чтобы украсить ее. Вы, наверное, уже знакомы с концепцией объектов-оболочек, и, по сути, именно этим и является Декоратор.
Refcard Designs Patterns
Для лучшего обзора самых популярных шаблонов дизайна, лучше всего начать с Refcard Designs Patterns от DZone .
Образец Декоратора
Декоратор известен как структурный шаблон, так как он используется для формирования больших структур объектов во многих разнородных объектах. Определение Decorator, представленное в оригинальной книге «Банды четырех» на DesignPatterns, гласит:
Позволяет динамически оборачивать объекты, чтобы изменить их существующие обязанности и поведение
Традиционно, вы могли бы рассмотреть подклассы как лучший способ приблизиться к этому — но будут случаи, когда подклассификация невозможна или нецелесообразна. Это приводит нас к принципу Open / Closed : классы должны быть открыты для расширения, но закрыты для модификации. Это хороший принцип, который нужно иметь в виду, поскольку он сохраняет стабильность вашего класса, но оставляет его открытым для расширения, если кто-то хочет добавить поведение.
Давайте посмотрим на определение диаграммы, прежде чем углубляться в детали.
Компонент определяет интерфейс для объектов , которые могут быть добавлены динамически responsibilties, а ConcreteComponent это просто реализация этого интерфейса. Декоратор имеет ссылку на компонент , а также соответствует интерфейсу компоненты. Это важная вещь, которую нужно помнить, поскольку Декоратор, по сути, оборачивает Компонент. ConcreteDecorator только добавляет обязанности к исходному компоненту.
Буду ли я использовать этот шаблон?
Шаблон Decorator следует использовать, когда:
- Обязанности и поведение объекта должны быть динамически модифицируемыми
- Конкретные реализации должны быть отделены от ответственности и поведения
Как упомянуто в предыдущем разделе, это может быть сделано путем создания подклассов. Но слишком много подклассов, безусловно, плохо. Когда вы добавите больше поведения в базовый класс, вы скоро столкнетесь с кошмаром обслуживания, поскольку для каждой возможной комбинации создается новый класс. Хотя декоратор может вызывать собственные проблемы, он предоставляет лучшую альтернативу слишком большому подклассу.
Так как это работает в Java?
Вы увидите декораторы, используемые в потоках ввода / вывода Java. Потоковые классы расширяют базовые подклассы, добавляя функции в потоковые классы.
В нашем примере мы будем использовать электронные письма для иллюстрации декоратора.
Сначала у нас есть интерфейс электронной почты, у которого есть метод getContents:
public interface IEmail{ public String getContents(); }
И мы предоставим конкретную реализацию для использования:
//concrete componentpublic class Email implements IEmail{ private String content; public Email(String content) { this.content = content; } @Override public String getContents() { //general email stuff return content; }}
Теперь мы создадим декоратор, который обернет базовую электронную почту дополнительной функциональностью. Мы смоделируем это как абстрактный класс и сохраним ссылку на базовую электронную почту.
public abstract class EmailDecorator implements IEmail{ //wrapped component IEmail originalEmail; }
Допустим, к электронным письмам, которые покидают внутренний сервер компании, в конце должен быть добавлен отказ от ответственности. Мы можем просто добавить декоратор для обработки этого:
//concrete decoratorpublic class ExternalEmailDecorator extends EmailDecorator{ private String content; public ExternalEmailDecorator(IEmail basicEmail) { originalEmail = basicEmail; } @Override public String getContents() { // secure original content = addDisclaimer(originalEmail.getContents()); return content; } private String addDisclaimer(String message) { //append company disclaimer to message return message + "\n Company Disclaimer"; } }
И если бы мы хотели создавать безопасные, зашифрованные сообщения, мы могли бы использовать другой декоратор:
//concrete decoratorpublic class SecureEmailDecorator extends EmailDecorator{ private String content; public SecureEmailDecorator(IEmail basicEmail) { originalEmail = basicEmail; } @Override public String getContents() { // secure original content = encrypt(originalEmail.getContents()); return content; } private String encrypt(String message) { //encrypt the string return encryptedMessage; } }
Итак, если наш клиент, отправляющий электронную почту, обнаруживает, что это сообщение выходит за пределы компании, мы можем вызвать соответствующего декоратора перед отправкой:
public class EmailSender{ public void sendEmail(IEmail email) { //read the email to-address, to see if it's going outside of the company //if so decorate it ExternalEmailDecorator external = new ExternalEmailDecorator(email); external.getContents(); //send }}
Остерегайтесь недостатков
Злоупотребление принципом Open / Closed может привести к абстрактному и сложному коду. Этот принцип действительно должен использоваться только там, где код менее всего может измениться.
Книга Design Patterns действительно указывает на пару недостатков этого шаблона. Декораторы могут привести к созданию системы с большим количеством меньших объектов, которые будут похожи на разработчика и создадут головную боль при обслуживании. Кроме того, Decorator и его вложенные компоненты не идентичны, поэтому тесты для типа объекта (instanceof) не пройдут.
Следующий
Следующим паттерном будет «Цепочка ответственности».
Наслаждайтесь всей серией «Design Patterns Uncovered»:
Образцы творчества
- Узнайте абстрактный шаблон фабрики
- Изучите Образец Строителя
- Изучите шаблон метода фабрики
- Изучите образец прототипа
- Изучите образец Синглтона
Структурные паттерны
- Узнайте шаблон адаптера
- Изучите Образец Моста
- Изучите составной шаблон
- Изучите Образец Декоратора
- Изучите Образ Фасада
- Выучите образец веса
- Изучите Образец Прокси
Поведенческие образцы
- Изучите Образец Цепочки Ответственности
- Изучите шаблон команд
- Изучите образец интерпретатора
- Изучите образец итератора
- Изучите Образец Посредника
- Выучите Образец Памяти
- Изучите Образец Наблюдателя
- Изучите Государственный Образец
- Узнайте шаблон стратегии
- Изучите шаблон метода шаблона
- Изучите образец посетителя