Какие категории паттернов существуют?
Паттерны делятся на три основные категории в зависимости от того, что они помогают делать:
🟢 Junior Level
Паттерны делятся на три основные категории в зависимости от того, что они помогают делать:
1. Порождающие (Creational) — скрывают ЧТО создаётся, КОГДА и КАК. Код не должен зависеть от конкретных классов через new.
- Как
Builder— пошаговое создание сложного объекта - Как
Singleton— гарантия одного экземпляра - Как
Factory— создание объектов через фабрику
2. Структурные (Structural) — помогают соединять классы
- Как
Adapter— делает совместимыми разные интерфейсы - Как
Decorator— добавляет функциональность обёрткой - Как
Proxy— заменяет объект суррогатом
3. Поведенческие (Behavioral) — решают: кто вызывает кого, когда и при каких условиях.
- Как
Strategy— замена алгоритмов - Как
Observer— подписка на события - Как
Iterator— перебор элементов
Простая аналогия: Строим дом
- Порождающие — как создать кирпичи, окна, двери
- Структурные — как соединить их вместе
- Поведенческие — как люди будут пользоваться домом
Когда НЕ думать в категориях категорий
Для простых CRUD-приложений категории паттернов избыточны. Используйте паттерн только когда он решает конкретную проблему.
🟡 Middle Level
1. Порождающие паттерны (Creational)
Фокус: Инкапсуляция процесса создания объектов
Зачем: Отделение системы от конкретных реализаций
// ❌ Без Factory — жесткая связь
User user = new User();
Order order = new Order();
// ✅ С Factory — гибкость
User user = userFactory.create();
Order order = orderFactory.create();
Ключевые паттерны:
Singleton— один экземплярFactory Method— создание через метод в подклассеAbstract Factory— создание семейств объектовBuilder— пошаговое созданиениеPrototype— копирование объекта
В Modern Java:
// Статические фабричные методы в интерфейсах
List<String> list = List.of("a", "b", "c"); // Вместо new ArrayList()
Optional<String> opt = Optional.of(value); // Factory Method
2. Структурные паттерны (Structural)
Фокус: Композиция классов в более крупные структуры
Зачем: Решение проблем несовместимости без наследования
// Decorator — добавление функциональности
InputStream input = new BufferedInputStream(
new FileInputStream("file.txt")
);
// Adapter — совместимость интерфейсов
List<String> list = Collections.enumeration(arrayList);
Ключевые паттерны:
Adapter— совмещение несовместимых интерфейсовDecorator— добавление обязанностей в runtimeProxy— суррогат для контроля доступаFacade— упрощённый интерфейс к подсистемеComposite— древовидная структура
В Spring:
// Proxy — основа всей "магии" Spring
@Transactional // Proxy вокруг бина
@Cacheable // Proxy с кэшированием
@Async // Proxy для асинхронности
3. Поведенческие паттерны (Behavioral)
Фокус: Алгоритмы и распределение обязанностей
Зачем: Управление динамикой передачи сигналов
// Strategy — замена алгоритмов
Comparator<String> byLength = (a, b) -> a.length() - b.length();
list.sort(byLength);
// Observer — подписка на события
button.addActionListener(e -> System.out.println("Clicked!"));
Ключевые паттерны:
Strategy— семейство алгоритмовObserver— подписка на измененияChain of Responsibility— цепочка обработчиковState— поведение зависит от состоянияTemplate Method— скелет алгоритма
4. Расширенная классификация
Concurrency Patterns:
// Read-Write Lock
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// Producer-Consumer
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
Architectural Patterns:
MVC— Model-View-ControllerHexagonal Architecture— порты и адаптерыCQRS— разделение чтения/записи
Cloud-Native Patterns:
Circuit Breaker— защита от каскадных сбоевSaga— распределённые транзакцииRetry— повторные попыткиBulkhead— изоляция ресурсов
🔴 Senior Level
Архитектурный смысл категорий
Категория = уровень управления сложностью:
| Категория | Какую проблему решает | Code Smell |
|---|---|---|
| Creational | Жёсткая связь при создании | Много new в бизнес-коде |
| Structural | Сложность связей и иерархий | Взрыв подклассов, несовместимость |
| Behavioral | Логика взаимодействия | Огромные switch/if-else |
Creational: Dependency Inversion на практике
DIP (Dependency Inversion Principle) — принцип инверсии зависимостей: завись от абстракций, не от деталей. OCP (Open/Closed Principle) — принцип открытости/закрытости: открыт для расширения, закрыт для модификации.
Если в бизнес-коде много `new` → нарушение DIP
Решение:
1. Simple Factory (статический метод)
2. Factory Method (наследование)
3. Abstract Factory (семейства)
4. DI Container (Spring)
Эволюция:
// Уровень 1: Simple Factory
public static UserService create() { return new UserServiceImpl(); }
// Уровень 2: Factory Method
public abstract class Factory { abstract UserService create(); }
// Уровень 3: Abstract Factory
public interface AppFactory {
UserService createUser();
OrderService createOrder();
PaymentService createPayment();
}
// Уровень 4: DI Container
@Component
public class UserService { } // Spring сам создаст
Structural: Композиция vs Наследование
Decorator вместо наследования:
// ❌ Наследование → взрыв классов
class BufferedFileInputStream extends FileInputStream { }
class EncryptedFileInputStream extends FileInputStream { }
class BufferedEncryptedFileInputStream extends FileInputStream { }
// → 2^n классов для n функций!
// ✅ Decorator → композиция
new BufferedInputStream(
new CipherInputStream(
new FileInputStream("file.txt")
)
)
// → n классов для n функций
Behavioral: Полиморфизм вместо switch
// ❌ Процедурный подход
switch (paymentType) {
case CREDIT_CARD: processCreditCard(); break;
case PAYPAL: processPayPal(); break;
case CRYPTO: processCrypto(); break;
}
// ✅ ООП подход (Strategy)
interface PaymentStrategy { void process(); }
class CreditCardPayment implements PaymentStrategy { ... }
class PayPalPayment implements PaymentStrategy { ... }
paymentStrategy.process(); // Полиморфизм
Modern Java:
// Enum Map Strategy
Map<PaymentType, PaymentStrategy> strategies = Map.of(
CREDIT_CARD, this::processCreditCard,
PAYPAL, this::processPayPal,
CRYPTO, this::processCrypto
);
strategies.get(type).process();
Взаимосвязь категорий в реальных системах
Spring Context как “Мета-фабрика”:
ApplicationContext (Creational)
→ создаёт бины
→ оборачивает в Proxy (Structural)
→ которые управляют поведением (Behavioral)
Типичная цепочка:
Abstract Factory (Creational)
→ возвращает Proxy (Structural)
→ который оборачивает бизнес-логику
→ управляемую через Strategy (Behavioral)
→ собираемую через Builder (Creational)
→ с Chain of Responsibility (Behavioral) для валидации
Performance Implications
JIT и полиморфизм:
Monomorphic call (1 реализация)
→ JIT инлайнит код
→ 0 накладных расходов
Bimorphic call (2 реализации)
→ JIT всё ещё оптимизирует
→ Минимальные расходы
Megamorphic call (>2 реализаций)
→ Косвенный вызов через vtable
→ Измеримая просадка по CPU
Оптимизация для Hot-path:
// Вместо интерфейса → enum
public enum CompressionType {
GZIP { @Override public byte[] compress(byte[] data) { ... } },
LZ4 { @Override public byte[] compress(byte[] data) { ... } };
public abstract byte[] compress(byte[] data);
}
// → JIT лучше оптимизирует enum switch table
Cloud-Native Patterns Deep Dive
Circuit Breaker:
@CircuitBreaker(name = "backendA", fallbackMethod = "fallback")
public String getData() {
return restTemplate.getForObject("http://service-a", String.class);
}
Saga Pattern:
Order Service → создать заказ
↓
Payment Service → списать деньги
↓
Inventory Service → зарезервировать товар
↓ (если ошибка)
Compensating Transactions → откатить всё
Production Experience
Реальный сценарий: Категоризация помогла найти корень проблемы
- Система: 200+ классов, сложно понять что где
- Анализ по категория:
- Creational: 30 Factory классов (overengineering)
- Structural: 50 Decorator (нужно)
- Behavioral: 80 Strategy (дублирование)
- Решение:
- Заменили Factory на DI
- Consolidate Strategy → Map
- Результат: -40% классов, +читаемость
Best Practices
- Определяйте категорию при выборе паттерна
- Creational → боритесь с
newв бизнес-коде - Structural → композиция > наследование
- Behavioral → полиморфизм > switch
- Cloud-Native обязательны для микросервисов
- Проверяйте взаимосвязи между паттернами
- Думайте о JIT при выборе реализации
- Modern Java упрощает многие категории
Резюме для Senior
- Creational = борьба с жёсткой связью при создании
- Structural = управление сложностью связей
- Behavioral = управление логикой взаимодействия
- Категория = уровень управления архитектурной сложностью
- Взаимосвязь: паттерны разных категорий работают вместе
- JIT: megamorphic calls влияют на производительность
- Cloud-Native паттерны критичны для микросервисов
- Spring Context = мега-фабрика всех категорий
🎯 Шпаргалка для интервью
Обязательно знать:
- Три основные категории: Creational (создание объектов), Structural (композиция классов), Behavioral (взаимодействие)
- Creational скрывают процесс создания, Structural решают проблемы совместимости, Behavioral управляют алгоритмами
- В Modern Java: Factory Method заменяется Supplier
, Singleton — DI-контейнером (Spring @Component) - Spring @Transactional, @Cacheable, @Async работают через Proxy (Structural паттерн)
- Cloud-Native паттерны: Circuit Breaker, Saga, Retry, Bulkhead — обязательны для микросервисов
- Категории помогают определять корень архитектурных проблем и выбирать правильное решение
- Эволюция: Simple Factory → Factory Method → Abstract Factory → DI Container
Частые уточняющие вопросы:
- Какой паттерн заменяет switch в бизнес-коде? — Strategy (Behavioral), Map<Enum, Function>
- Что такое megamorphic call? — Вызов метода с >2 реализациями интерфейса, JIT не может инлайнить
- Как Spring управляет созданием бинов? — ApplicationContext как “мега-фабрика” всех категорий паттернов
- Когда категории паттернов избыточны? — В простых CRUD-приложениях и прототипах
Красные флаги (НЕ говорить):
- “Мне не нужны категории, я пишу код без паттернов” — незнание архитектурных основ
- “Все паттерны устарели с приходом Spring” — Spring сам использует паттерны под капотом
- “Creational паттерны нужны только в Java” — они применимы в любом ООП языке
- “Структурные паттерны — это только для GUI” — Adapter, Decorator, Proxy везде в Spring
Связанные темы:
- [[1. Что такое паттерны проектирования]] — общее введение и уровни паттернов
- [[3. Что такое Singleton]] — Creational паттерн
- [[12. В чём преимущество Decorator перед наследованием]] — Structural паттерн
- [[10. Когда использовать Strategy]] — Behavioral паттерн
- [[14. Какие типы Proxy существуют]] — Structural паттерн в Spring