В чому різниця між State та Strategy?
Обидва патерни схожі, але мета у них різна:
🟢 Junior Level
Обидва патерни схожі, але мета у них різна:
Strategy — вибір алгоритму ззовні (клієнт вирішує):
// Клієнт сам обирає стратегію
order.setPaymentStrategy(new CreditCardPayment()); // Ззовні
order.pay();
State — зміна поведінки зсередини (об’єкт сам вирішує):
// Об'єкт сам змінює стан
order.process(); // Всередині: якщо оплачено → відправити, якщо ні → чекати
Проста аналогія:
- Strategy: Ви обираєте маршрут у навігаторі (на машині/пішки)
- State: Світлофор сам змінює колір (червоний → жовтий → зелений)
🟡 Middle Level
Strategy: Зовнішнє керування
interface SortStrategy { void sort(List<Integer> list); }
class QuickSort implements SortStrategy { ... }
class MergeSort implements SortStrategy { ... }
// КЛІЄНТ вирішує
List<Integer> data = new ArrayList<>();
Sorter sorter = new Sorter();
sorter.setStrategy(new QuickSort()); // Клієнт обрав
sorter.sort(data);
State: Внутрішнє керування
interface OrderState { void process(Order order); }
class Order {
private OrderState state;
void setState(OrderState s) { this.state = s; }
void process() { state.process(this); } // делегування стану
}
class NewState implements OrderState {
public void process(Order order) {
// Перехід у наступний стан
// Пряме створення станів (new PaidState()) — антипатерн (tight coupling).
// Правильний підхід: transitions через Registry/Factory.
order.setState(new PaidState());
}
}
class PaidState implements OrderState {
public void process(Order order) {
order.setState(new ShippedState());
}
}
// ОБ'ЄКТ сам змінює стан
Order order = new Order();
order.setState(new NewState());
order.process(); // Всередині: NewState → PaidState
order.process(); // Всередині: PaidState → ShippedState
Порівняння
| Критерій | Strategy | State |
|---|---|---|
| Хто обирає | Клієнт | Сам об’єкт |
| Коли змінюється | Runtime, за бажанням | При зміні стану |
| Залежність | Стратегії не знають одна про одну | Стани знають про переходи |
| Мета | Заміна алгоритму | Керування поведінкою |
🔴 Senior Level
Architecture Intent
Strategy = Dependency Injection для алгоритмів
→ Впроваджуємо потрібний алгоритм
→ Алгоритми незалежні
State = Finite State Machine
→ Стани пов'язані переходами
→ Кожен стан знає про наступні
Coupling Differences
// Strategy: стратегії НЕ знають одна про одну
class CreditCardPayment implements PaymentStrategy { }
class PayPalPayment implements PaymentStrategy { }
// Немає залежностей між ними
// State: стани знають про переходи
class NewState implements OrderState {
public void process(Order order) {
order.setState(new PaidState()); // Знає про PaidState!
}
}
// Пов'язані через контекст
Production Experience
Реальний сценарій:
- Замовлення: 5 станів
- Спочатку використовували Strategy → клієнт керував переходами
- Баги: замовлення з “Доставлено” перейшло у “Нове”
- Рішення: State machine з валідацією переходів
- Результат: неможливі невалідні переходи
Best Practices
- Strategy для заміни алгоритмів
- State для керування життєвим циклом
- Enum для простих станів
- Spring Statemachine для enterprise
- Валідація переходів у State
Резюме для Senior
- Strategy = клієнт обирає алгоритм
- State = об’єкт керує своєю поведінкою
- Strategy = незалежні алгоритми
- State = пов’язані переходи між станами
- State Machine запобігає невалідним переходам
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Strategy — клієнт обирає алгоритм ззовні, State — об’єкт змінює поведінку зсередини
- Strategy: алгоритми незалежні один від одного, State: стани пов’язані переходами
- Strategy = Dependency Injection для алгоритмів, State = Finite State Machine
- State запобігає невалідним переходам (не можна з “Доставлено” перейти у “Нове”)
- Template Method — заміна частин алгоритму через наслідування, Strategy — весь алгоритм через композицію
- Для простих станів: Enum з абстрактними методами, для enterprise: Spring Statemachine
- Пряме створення станів (new PaidState()) — tight coupling, правильно: transitions через Registry/Factory
Часті уточнювальні запитання:
- Коли використовувати State замість Strategy? — Коли є життєвий цикл з валідними переходами (замовлення, документ)
- Чому стани мають знати про переходи? — Інакше клієнт може зробити невалідний перехід
- Чим Template Method відрізняється від Strategy? — Template Method = частини алгоритму (наслідування), Strategy = весь алгоритм (композиція)
- Що робити якщо переходів дуже багато? — State machine з таблицею переходів, Spring Statemachine
Червоні прапорці (НЕ говорити):
- “Strategy і State — це одне й те саме” — принципово різні мета і керування
- “Клієнт повинен керувати станами” — тоді це Strategy, не State
- “State machine — це overengineering” — при 5+ станах без нього будуть баги з переходами
- “Стани не повинні знати один про одного” — тоді неможливо валідувати переходи
Пов’язані теми:
- [[10. Коли використовувати Strategy]] — основний патерн Strategy
- [[15. Що таке патерн Iterator]] — перебір станів
- [[2. Які категорії патернів існують]] — Behavioral патерни
- [[16. Які антипатерни ви знаєте]] — Sequential Coupling
- [[1. Що таке патерни проектування]] — Behavioral категорія