Перейти к основному содержимому

Что это такое

Паттерн Decorator добавляет объекту поведение, оборачивая его в другой объект с тем же интерфейсом. Каждая обёртка делает свою маленькую добавку и передаёт вызов дальше — тому, что она оборачивает.

Поскольку обёртка и обёрнутый объект имеют один интерфейс, обёртки складываются в любых сочетаниях — как слои одежды.

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


Пример: оборачиваем уведомитель

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

Слои вокруг ядра

Запись new WithLog(new WithSMS(new EmailNotifier())) читается изнутри наружу: почта в ядре, смс вокруг неё, журнал — самый внешний слой. Вывод показывает именно этот порядок: строка журнала, письмо, затем смс. Любой слой можно добавить, убрать или переставить, не трогая остальные.

Prompt
Напишите программу на TypeScript, показывающую паттерн Decorator: интерфейс Notifier с методом send, простой класс EmailNotifier, класс WithLog, который печатает строку журнала перед тем, как передать вызов дальше, и класс WithSMS, который дополнительно печатает строку смс после вызова. Оберните WithLog вокруг WithSMS, а WithSMS вокруг почтового уведомителя, и отправьте одно сообщение.
Вывод: программа на TypeScript и захваченный вывод
Layers around a core

Когда его использовать

Используйте его, чтобы добавить необязательное и сочетаемое поведение — журналирование, кеширование, повторные попытки, метрики — вокруг ядра, которое вы не хотите менять. Middleware в веб-серверах — это в точности данный паттерн.

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


Плюсы и минусы

Плюсы: поведение добавляется без изменения основного класса; слои свободно сочетаются; каждый слой мал и тестируется отдельно.

Минусы: глубокую стопку обёрток трудно отлаживать — вызов проходит долгий путь, прежде чем что-то сделать; строки создания объектов становятся длинными.