Шаблоны проектирования (Design Patterns)

Проверенные типовые решения частых задач проектирования кода: не готовый код, а схема, которую адаптируют под задачу.

Шаблон проектирования (design pattern) — описание проверенного решения задачи, которая регулярно встречается при проектировании программ. Это не библиотека и не готовый код, а схема: какие объекты участвуют, как они связаны и чем такое решение хорошо. Шаблоны дают разработчикам общий язык: фраза «здесь нужен адаптер» сразу объясняет коллеге целый кусок архитектуры.

Самый известный каталог — книга «Приемы объектно-ориентированного проектирования» (Design Patterns, 1994) четырех авторов, которых называют «бандой четырех» (Gang of Four). В ней описаны 23 шаблона для объектно-ориентированного программирования.

Три группы классических шаблонов

  • Порождающие — как создавать объекты. Фабричный метод решает, какой именно объект создать; Строитель собирает сложный объект по шагам; Одиночка (Singleton) гарантирует единственный экземпляр.
  • Структурные — как соединять объекты. Адаптер приводит чужой интерфейс к нужному; Фасад дает простой вход в сложную подсистему; Декоратор добавляет поведение, не меняя класс; Заместитель (Proxy) контролирует доступ к объекту.
  • Поведенческие — как объекты взаимодействуют. Наблюдатель рассылает уведомления подписчикам; Стратегия позволяет подменять алгоритм; Команда превращает действие в объект, который можно отложить или отменить.

Пример: Адаптер

Новая система ждет данные о клиенте в одном формате, а старая учетная система отдает их в другом. Переписывать старую систему дорого. Адаптер — небольшой класс, который принимает запрос в новом формате, вызывает старую систему и переводит ответ. Остальной код ничего не знает о старом формате. Так часто поступают при миграции и импортозамещении: старые и новые системы какое-то время работают вместе.

Пример: Стратегия

Расчет доставки зависит от способа: курьер, пункт выдачи, почта. Вместо длинной цепочки условий каждый способ оформляют отдельным классом с общим методом «рассчитать». Добавить новый способ — значит добавить класс, не трогая работающий код. В основе лежит полиморфизм.

Шаблоны за пределами классов

Идея шаблонов распространилась на архитектуру целых систем. MVC разделяет данные, отображение и управление; Репозиторий прячет работу с базой данных; в микросервисах используют API-шлюз, «предохранитель» (Circuit Breaker), который перестает вызывать упавший сервис, и очередь сообщений между сервисами.

Когда шаблоны вредят

Шаблон — ответ на конкретную проблему. Если проблемы нет, он добавляет лишние классы и усложняет код. Одиночку, например, часто критикуют: это скрытая глобальная переменная, которая мешает тестам. Хорошее правило — начинать с простого решения и применять шаблон, когда код действительно начинает повторяться или разрастаться.