GoF паттерны в Java - большой практический гид
Этот материал объединяет практику по паттернам из серии 122-139 в один рабочий справочник. Цель статьи — дать инженерный инструмент выбора по типовым проблемам в коде. Для первого знакомства с Factory, Observer, Strategy и остальными «рабочими лошадками» начните с Частые паттерны GoF в реальных проектах.
Как читать этот материал
Маршрут для быстрого старта:
- Смотрите карту выбора "какая проблема -> какой паттерн".
- Сверяете сценарий с таблицей "когда использовать".
- Проверяете анти-признаки, чтобы не ввести паттерн раньше времени.
- Переходите в узкую статью с кодом по ссылке.
Карта выбора паттерна
Научный минимум без перегруза
В академической формулировке паттерн проектирования - это повторяемое архитектурное решение в заданном контексте с известными компромиссами.
Практически это означает три вещи:
- паттерн решает типовую проблему, а не любую;
- паттерн усиливает одни свойства системы ценой других;
- паттерн оценивается по влиянию на стоимость изменений, а не по "красоте 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 хранение состояния |
Анти-паттерн карта
Чек-лист архитектурного ревью
- Паттерн введен под конкретный повторяющийся сценарий, а не "на будущее".
- Есть явные границы ответственности между ролями паттерна.
- Указаны компромиссы и известные риски.
- Добавлены тесты на критичные ветки (конфигурация, порядок вызовов, откат).
- Документирована точка расширения для следующего разработчика.
Где продолжить углубление
- Порождающие: 111, 130, 134, 135, 136, 138
- Структурные: 112, 129, 128, 131, 132, 133, 137
- Поведенческие: 113, 122, 123, 124, 125, 126, 127, 139
Применяйте паттерны как гипотезы. Берите одну реальную боль из кода, внедряйте минимальный каркас, меряйте скорость следующего изменения и только после этого масштабируйте решение на соседние модули.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Паттерн — это повторяющийся шаблон, узор или схема. Паттерны встречаются повсюду — в природе, архитектуре, поведении людей и, конечно, в программировании. Порождающие паттерны проектирования — это группа шаблонов, направленных на решение задач, связанных с созданием объектов. Структурные паттерны — это группа шаблонов проектирования, решающих задачи организации классов и объектов таким образом, чтобы обеспечить гибкую архитектуру программного обеспечения. Поведенческие паттерны — это группа шаблонов проектирования, которые определяют способы взаимодействия объектов и распределения ответственности между ними. Архитектурные паттерны — это проверенные решения для организации структуры программного обеспечения. Интеграция систем — одна из центральных задач в современной разработке программного обеспечения. Паттерны доменного моделирования представляют собой проверенные решения для организации бизнес-логики в программных системах. Паттерн Strategy в C# — классическая реализация через интерфейс, замена на Func и Action, DI и критерии выбора без лишних абстракций. Паттерн Iterator в C# — ручной IEnumerator, генерация итератора компилятором через yield return, ленивость, LINQ и случаи, когда класс писать всё же нужно. Abstract Factory в C# и .NET — классическая схема через интерфейсы, замена через DI-контейнер, фабричный делегат и keyed services в .NET 8. Паттерн Command в C# — классическая схема, делегаты, MediatR, очередь задач, undo и критерии выбора между объектом команды и простым вызовом сервиса. Паттерн Observer в C# — event и делегаты, IObservable IObserver, слабая связанность, отписка и как не поймать утечки памяти в долгоживущих сервисах.Обзор паттернов проектирования
Порождающие паттерны
Структурные паттерны
Поведенческие паттерны
Архитектурные паттерны
Паттерны интеграции внешних систем
Паттерны проектирования доменных моделей
Стратегия в C#
Итератор в C#
Фабрика в C#
Команда в C#
Наблюдатель в C#