В чем разница между паттернами проектирования «Состояние» и «Стратегия»?

«В чем разница между паттернами проектирования «Состояние» и «Стратегия»?» — вопрос из категории Паттерны, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерны «Состояние» (State) и «Стратегия» (Strategy) имеют схожую структуру (композиция и делегирование), но решают разные задачи.

Паттерн «Состояние»

  • Назначение: Позволять объекту менять свое поведение при изменении его внутреннего состояния. Объект будет вести себя как будто он изменил класс.
  • Взаимодействие: Конкретные состояния знают друг о друге и могут инициировать переход контекста в другое состояние.
  • Акцент: На управлении жизненным циклом и переходами между состояниями объекта (например, заказ: New -> Paid -> Shipped).

Пример (Состояние заказа):

interface OrderState {
    void cancel(OrderContext context);
    void ship(OrderContext context);
}

class PaidState implements OrderState {
    public void cancel(OrderContext context) {
        // Логика отмены оплаченного заказа
        context.setState(new CancelledState()); // Переход в новое состояние
    }
    public void ship(OrderContext context) {
        context.setState(new ShippedState()); // Переход
    }
}
// Контекст хранит текущее состояние
class OrderContext {
    private OrderState currentState;
    public void setState(OrderState state) { this.currentState = state; }
    public void cancel() { currentState.cancel(this); } // Делегирование
}

Паттерн «Стратегия»

  • Назначение: Определять семейство алгоритмов, инкапсулировать каждый из них и делать их взаимозаменяемыми. Позволяет изменять алгоритм независимо от клиента, который его использует.
  • Взаимодействие: Конкретные стратегии не знают друг о друге. Клиент (контекст) явно выбирает, какую стратегию использовать.
  • Акцент: На вариативности поведения объекта (например, разные алгоритмы сортировки, способы оплаты).

Пример (Стратегия оплаты):

interface PaymentStrategy {
    void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
    public void pay(double amount) { /* Обработка карты */ }
}
class PayPalPayment implements PaymentStrategy {
    public void pay(double amount) { /* Вызов API PayPal */ }
}

class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy; // Клиент выбирает стратегию
    }
    public void checkout(double amount) {
        paymentStrategy.pay(amount); // Делегирование
    }
}

Сводка различий

Критерий Состояние (State) Стратегия (Strategy)
Цель Управление поведением в зависимости от состояния объекта Предоставление различных взаимозаменяемых алгоритмов
Управление переходами Внутри самих состояний Внешнее, со стороны клиента контекста
Осведомленность Состояния знают о других состояниях для переходов Стратегии независимы и не знают о других
Изменение поведения Автоматическое, как следствие изменения состояния Явное, по выбору клиента

Проще говоря: State — это о том, кто вы (и ваше поведение меняется автоматически), а Strategy — о том, что вы делаете (и вы сами выбираете, как это делать).