Які категорії патернів існують?
Патерни поділяються на три основні категорії залежно від того, що вони допомагають робити:
🟢 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