GoF паттерны в Java - большой практический гид
Модель и масштаб — Основы БД, опорные темы, проектирование БД, пакетная работа. Карта — о разделе.
Этот материал объединяет практику по паттернам из серии 122-139 в один рабочий справочник. Цель статьи — дать инженерный инструмент выбора по типовым проблемам в коде. Для первого знакомства начните с принципов перед паттернами и десяти частых шаблонов; составные схемы и MVC — в отдельной статье.
Как читать этот материал
Маршрут для быстрого старта:
- Смотрите карту выбора "какая проблема -> какой паттерн".
- Сверяете сценарий с таблицей "когда использовать".
- Проверяете анти-признаки, чтобы не ввести паттерн раньше времени.
- Переходите в узкую статью с кодом по ссылке.
Карта выбора паттерна
Научный минимум без перегруза
В академической формулировке паттерн проектирования - это повторяемое архитектурное решение в заданном контексте с известными компромиссами.
Практически это означает три вещи:
- паттерн решает типовую проблему, а не любую;
- паттерн усиливает одни свойства системы ценой других;
- паттерн оценивается по влиянию на стоимость изменений, а не по "красоте UML".
Если после внедрения стало быстрее вносить изменение без каскада правок, паттерн сработал.
Порождающие паттерны в Java
Factory Method
- Нужен, когда базовый класс знает процесс, но не конкретный тип продукта.
- Дает расширение через подклассы по OCP.
- Риск: много мелких
*Creatorклассов.
Подробно: Factory Method в Java.
Abstract Factory
- Нужен, когда создается семейство совместимых объектов.
- Типичный кейс — AWS/Firebase, тема UI A/B, драйверы платформ.
- Риск: трудно добавить новый тип продукта в семейство.
Подробно: Abstract Factory в Java.
Builder
- Нужен для объектов с большим числом опций и валидацией перед созданием.
- Особенно полезен для immutable-конфигураций.
- Риск: дублирование полей в
BuilderиProduct.
Подробно: Builder в Java.
Prototype
- Нужен при дорогой инициализации и массовом тиражировании похожих объектов.
- Ключевая инженерная тема: deep copy vs shallow copy.
- Риск: случайное совместное владение изменяемыми вложенными объектами.
Подробно: Prototype в Java.
Singleton
- Нужен, если действительно требуется один экземпляр по доменной природе.
- В Java обычно выбирают
static final, holder idiom илиenum. - Риск — глобальное состояние, скрытые зависимости, сложные тесты.
Подробно: Singleton в Java.
Структурные паттерны в Java
Adapter
- Когда внешний SDK не совпадает с вашим контрактом.
- Убирает утечку чужого API в доменный слой.
- Риск: адаптер превращается в "склад костылей" при миграции без границ.
Подробно: Adapter в Java.
Bridge
- Когда есть две независимые оси изменений (
тип x реализация). - Снижает комбинаторный взрыв классов.
- Риск: избыточен, если ось изменения только одна.
Подробно: Bridge в Java.
Composite
- Когда модель естественно древовидна — оргструктура, файловая система, UI.
- Позволяет одинаково обрабатывать лист и контейнер.
- Риск: ограничения состава дочерних узлов уходят в runtime-проверки.
Подробно: Composite в Java.
Decorator
- Когда поведение комбинируется в runtime — лог, кеш, метрики.
- Альтернатива взрыву подклассов.
- Риск: длинная цепочка оберток ухудшает трассировку.
Подробно: Decorator в Java.
Facade
- Когда нужна одна "точка входа" к сложной подсистеме.
- Снижает связность между слоями и делает API сценарно-ориентированным.
- Риск: фасад может превратиться в God Object.
Подробно: Facade в Java.
Proxy
- Когда нужен контроль доступа, кеширование, lazy или remote-вызов.
- Работает как суррогат с тем же интерфейсом.
- Риск: несколько слоев прокси усложняют отладку.
Подробно: Proxy в Java.
Поведенческие паттерны в Java
Strategy
- Нужен для подмены алгоритма в runtime.
- Убирает
if-elseпо типу поведения. - Риск: лишние классы при двух тривиальных вариантах.
Подробно: Strategy в Java.
Command
- Когда действие нужно хранить, повторять, ставить в очередь, отменять.
- Основа undo/redo и асинхронных пайплайнов.
- Риск: рост числа классов-команд.
Подробно: Command в Java.
Observer
- Для модели "один ко многим" при изменении состояния.
- Хорош для событийной декомпозиции.
- Риск: непредсказуемый порядок уведомлений и утечки без unsubscribe.
Подробно: Observer в Java.
Mediator
- Убирает прямые связи "каждый с каждым" через центральный координатор.
- Хорош для сложной оркестрации UI/чатов.
- Риск: медиатор разрастается в центр всей бизнес-логики.
Подробно: Mediator в Java.
Memento
- Фиксирует снимок состояния для отката.
- Подходит для checkpoints и истории правок.
- Риск: рост памяти при больших состояниях и длинной истории.
Подробно: Memento в Java.
Iterator
- Унифицирует обход разных структур без раскрытия внутреннего устройства.
- Подходит для пагинации и ленивой выборки.
- Риск:
ConcurrentModificationExceptionпри мутациях коллекции во время обхода.
Подробно: Iterator в Java.
Chain of Responsibility
- Проводит запрос через последовательность обработчиков.
- Полезен для пайплайнов фильтрации и авторизации.
- Риск: "черная дыра", если нет терминального обработчика.
Подробно: Chain of Responsibility в Java.
Кросс-сравнение паттернов, которые чаще путают
| Пара | Ключевое различие |
|---|---|
| Factory Method vs Abstract Factory | Один продукт vs семейство продуктов |
| Builder vs Factory Method | Пошаговая сборка vs выбор конкретного типа |
| Strategy vs Bridge | Замена алгоритма vs развязка двух иерархий |
| Decorator vs Proxy | Расширение поведения vs контроль доступа/жизненного цикла |
| Observer vs Mediator | Рассылка подписчикам vs центральная координация участников |
| Command vs Memento | Хранение действия vs хранение состояния |
Анти-паттерн карта
Чек-лист архитектурного ревью
- Паттерн введен под конкретный повторяющийся сценарий, а не "на будущее".
- Есть явные границы ответственности между ролями паттерна.
- Указаны компромиссы и известные риски.
- Добавлены тесты на критичные ветки (конфигурация, порядок вызовов, откат).
- Документирована точка расширения для следующего разработчика.
Где продолжить углубление
- Порождающие: Порождающие паттерны, Паттерн "Строитель" (Builder) в Java — сложная конфигурация без telescoping constructor, Паттерн "Прототип" (Prototype) в Java — копирование вместо создания с нуля, Паттерн "Абстрактная фабрика" (Abstract Factory) в Java — семейства совместимых клиентов, Паттерн "Фабричный метод" (Factory Method) в Java — создание через подклассы, Паттерн "Одиночка" (Singleton) в Java — один экземпляр и контролируемый доступ
- Структурные: Структурные паттерны, Паттерн "Фасад" в Java — один метод над подсистемой, Паттерн "Заместитель" (Proxy) в Java — доступ, кэш и lazy loading, Паттерн "Мост" (Bridge) в Java — тип уведомления и канал доставки, Паттерн "Компоновщик" (Composite) в Java — дерево отдела и единый интерфейс, Паттерн "Декоратор" (Decorator) в Java — расширение поведения без наследования, Паттерн "Адаптер" (Adapter) в Java — совместимость с легаси и внешними SDK
- Поведенческие: Поведенческие паттерны, Паттерн "Цепочка обязанностей" в Java — фильтры и обработчики, Паттерн "Итератор" в Java — Iterable, пагинация и for-each, Паттерн "Посредник" в Java — чат-комната и DispatcherServlet, Паттерн "Мементо" в Java — снимки состояния и undo, Паттерн "Команда" в Java — undo в редакторе и очередь действий, Паттерн "Наблюдатель" в Java — подписчики и ApplicationEvent, Паттерн "Стратегия" (Strategy) в Java — выбор алгоритма в runtime
Применяйте паттерны как гипотезы. Берите одну реальную боль из кода, внедряйте минимальный каркас, меряйте скорость следующего изменения и только после этого масштабируйте решение на соседние модули.