Паттерны проектирования
16. Паттерн «Декоратор» (Decorator)
Хорошо спроектированный класс отвечает за определенную функциональность, не распыляясь на решение второстепенных задач. Но что делать, если второстепенные задачи, такие как логирование, кэширование, замеры времени исполнения, проникают в код класса и непомерно увеличивают сложность реализации? Можно выделить эти аспекты поведения во вспомогательные классы, но все равно останется проблема их координации. Паттерн «Декоратор» элегантно решает задачу нанизывания одних обязанностей на другие.
Назначение: динамически добавляет объекту новые обязанности. Является гибкой альтернативой порождению подклассов с целью расширения функциональности.
Причины использования:
Идея паттерна «Декоратор» в том, что у интерфейса появляется два вида реализаций: основная реализация бизнес-функциональности и набор классов-декораторов, которые реализуют тот же интерфейс, но довольно специфическим образом. Декоратор принимает в конструкторе тот же самый интерфейс, а в реализации делегирует работу декорируемому объекту с присоединением некоторого поведения до или после вызова метода. При этом клиенты интерфейса будут работать с ним, как и раньше, не замечая наличия дополнительного поведения.
Классическая диаграмма приведена на рисунке ниже:
-
Component — базовый класс компонента, чьё поведение будет расширяться декораторами;-
Client — работает с компонентом, не зная о существовании декораторов;-
ConcreteComponent — конкретная реализация компонента;-
Decorator — базовый класс декоратора, предназначенный для расширения поведения компонента;-
ConcreteDecoratorA, ConcreteDecoratorB — конкретные декораторы, которые добавляют декорируемому объекту специфическое поведение.Применимость
Декораторы применяются для добавления всем методам интерфейса некоторого поведения, которое не является частью основной функциональности. Они отлично подходят для решения следующих задач:
- кэширования результатов работы;
- замера времени исполнения методов;
- логирования аргументов;
- управления доступом пользователей;
- модификации аргументов или результата работы методов упаковки/распаковки, шифрования и т. п.
Недостатки декораторов
1. Чувствительность к порядку. Код инициализации декораторов очень важен, поскольку именно в процессе создания определяются вложенность и порядок исполнения разных декораторов. Наличие декораторов делает процесс инициализации компонентов более сложным. Если есть ряд предустановленных конфигураций создания объекта, можно выделить их в фабричный метод.
2. Сложность отладки. Разработчику, незнакомому с этим паттерном, замер времени исполнения или кэширование результатов декораторами может показаться чёрной магией. Отлаживать проблемы, которые возникли внутри декоратора, может быть довольно сложно.
3. Увеличение сложности. Декоратор является довольно тяжеловесным паттерном, к которому стоит прибегать тогда, когда выделяемый аспект поведения достаточно сложен. Если нужно кэшировать результаты в одном из десяти методов, то сложность, привнесенная декоратором, будет неоправданной.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 14.