В чём разница между 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 pattern]] — перебор состояний
- [[2. Какие категории паттернов существуют]] — Behavioral паттерны
- [[16. Какие антипаттерны вы знаете]] — Sequential Coupling
- [[1. Что такое паттерны проектирования]] — Behavioral категория