← Назад к вопросам

В чем разница между шаблонами ООП Состояние и Стратегия?

2.8 Senior🔥 81 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Разница между паттернами State (Состояние) и Strategy (Стратегия)

Определения

State Pattern (Состояние) — поведенческий паттерн, позволяющий объекту изменять своё поведение в зависимости от своего внутреннего состояния.

Strategy Pattern (Стратегия) — поведенческий паттерн, позволяющий выбрать алгоритм во время выполнения программы.

На первый взгляд похожи

Оба паттерна используют полиморфизм и делегирование, но они решают разные проблемы.

Основное различие

State: Объект сам меняет своё поведение в зависимости от внутреннего состояния. Переход между состояниями может быть автоматическим.

Strategy: Клиент явно выбирает, какую стратегию (алгоритм) использовать. Стратегия не меняется сама.

Пример 1: State Pattern

// Интерфейс для состояний
public interface PaymentState {
    void pay(PaymentContext context, double amount);
}

// Конкретные состояния
public class WaitingState implements PaymentState {
    @Override
    public void pay(PaymentContext context, double amount) {
        System.out.println("Payment processing...");
        context.setState(new ProcessingState());
    }
}

public class ProcessingState implements PaymentState {
    @Override
    public void pay(PaymentContext context, double amount) {
        System.out.println("Payment confirmed! Amount: " + amount);
        context.setState(new CompletedState());
    }
}

public class CompletedState implements PaymentState {
    @Override
    public void pay(PaymentContext context, double amount) {
        System.out.println("Payment already completed");
    }
}

// Контекст - объект, который изменяет состояние
public class PaymentContext {
    private PaymentState state;
    
    public PaymentContext() {
        this.state = new WaitingState(); // Начальное состояние
    }
    
    public void pay(double amount) {
        state.pay(this, amount); // Делегирует текущему состоянию
    }
    
    public void setState(PaymentState state) {
        this.state = state; // Меняет состояние
    }
}

// Использование
PaymentContext payment = new PaymentContext();
payment.pay(100);  // WaitingState -> ProcessingState
payment.pay(200);  // ProcessingState -> CompletedState
payment.pay(300);  // CompletedState (остаётся в том же состоянии)

Пример 2: Strategy Pattern

// Интерфейс для стратегий
public interface SortingStrategy {
    void sort(int[] array);
}

// Конкретные стратегии
public class QuickSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("Sorting with QuickSort");
        // Реализация QuickSort
    }
}

public class MergeSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("Sorting with MergeSort");
        // Реализация MergeSort
    }
}

public class BubbleSortStrategy implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("Sorting with BubbleSort");
        // Реализация BubbleSort
    }
}

// Контекст - не меняет стратегию, просто её использует
public class SortingContext {
    private SortingStrategy strategy;
    
    // Стратегия устанавливается клиентом
    public SortingContext(SortingStrategy strategy) {
        this.strategy = strategy;
    }
    
    // Можно менять стратегию
    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void executeSort(int[] array) {
        strategy.sort(array);
    }
}

// Использование - КЛИЕНТ ВЫБИРАЕТ СТРАТЕГИЮ
int[] array = {5, 2, 8, 1, 9};

SortingContext sorter = new SortingContext(new QuickSortStrategy());
sorter.executeSort(array); // Использует QuickSort

sorter.setStrategy(new MergeSortStrategy());
sorter.executeSort(array); // Использует MergeSort

sorter.setStrategy(new BubbleSortStrategy());
sorter.executeSort(array); // Использует BubbleSort

Реальный пример: State vs Strategy

State: Торговый автомат

// Состояния торгового автомата
public interface VendingMachineState {
    void insertMoney(VendingMachine context, double amount);
    void selectProduct(VendingMachine context, String product);
    void dispense(VendingMachine context);
}

public class IdleState implements VendingMachineState {
    @Override
    public void insertMoney(VendingMachine context, double amount) {
        System.out.println("Money inserted: " + amount);
        context.setBalance(context.getBalance() + amount);
        context.setState(new MoneyInsertedState());
    }
    
    @Override
    public void selectProduct(VendingMachine context, String product) {
        System.out.println("Please insert money first");
    }
    
    @Override
    public void dispense(VendingMachine context) {
        System.out.println("Nothing to dispense");
    }
}

public class MoneyInsertedState implements VendingMachineState {
    @Override
    public void insertMoney(VendingMachine context, double amount) {
        System.out.println("Additional money inserted: " + amount);
        context.setBalance(context.getBalance() + amount);
    }
    
    @Override
    public void selectProduct(VendingMachine context, String product) {
        if (context.getBalance() >= context.getProductPrice(product)) {
            System.out.println("Product selected: " + product);
            context.setState(new DispensingState());
        } else {
            System.out.println("Insufficient funds");
        }
    }
    
    @Override
    public void dispense(VendingMachine context) {
        System.out.println("Please select a product");
    }
}

public class VendingMachine {
    private VendingMachineState state;
    private double balance;
    
    public VendingMachine() {
        this.state = new IdleState();
        this.balance = 0;
    }
    
    public void insertMoney(double amount) {
        state.insertMoney(this, amount);
    }
    
    public void selectProduct(String product) {
        state.selectProduct(this, product);
    }
    
    public void setState(VendingMachineState state) {
        this.state = state;
    }
    
    // Getters/Setters
    public double getBalance() { return balance; }
    public void setBalance(double balance) { this.balance = balance; }
    public double getProductPrice(String product) { return 10.0; }
}

Strategy: Система оплаты

// Стратегии оплаты
public interface PaymentStrategy {
    boolean pay(double amount);
}

public class CreditCardPayment implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("Paying " + amount + " with credit card");
        return true;
    }
}

public class PayPalPayment implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("Paying " + amount + " with PayPal");
        return true;
    }
}

public class BitcoinPayment implements PaymentStrategy {
    @Override
    public boolean pay(double amount) {
        System.out.println("Paying " + amount + " with Bitcoin");
        return true;
    }
}

// Контекст - клиент выбирает стратегию
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    // Клиент выбирает стратегию
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void checkout(double amount) {
        if (paymentStrategy != null) {
            paymentStrategy.pay(amount);
        } else {
            System.out.println("Payment method not selected");
        }
    }
}

// Использование
ShoppingCart cart = new ShoppingCart();

cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Клиент выбирает способ оплаты

cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50);

cart.setPaymentStrategy(new BitcoinPayment());
cart.checkout(75);

Таблица сравнения

АспектStateStrategy
НазначениеИзменение поведения при изменении состоянияВыбор алгоритма во время выполнения
Кто выбираетСам объект (автоматический переход)Клиент (явный выбор)
СостоянияТесно связаны, определяют друг другаНезависимы, параллельны
ПримерТорговый автомат, заказ, платёжСортировка, способ оплаты, шифрование
ПереходыМогут быть сложные, циклическиеОбычно линейные или без переходов
Количество объектовОбычно много состоянийОбычно несколько стратегий
Временная жизньМеняется часто во время жизни объектаУстановленная один раз или редко меняется

Сравнение кода

State: Состояние меняется автоматически

payment.pay(100);  // State 1 -> выполнен -> State 2
payment.pay(200);  // State 2 -> выполнен -> State 3
// Переходы управляются самим объектом

Strategy: Стратегия выбирается клиентом

sorter.setStrategy(new QuickSort());    // Клиент выбирает
sorter.setStrategy(new MergeSort());    // Клиент выбирает
sorter.setStrategy(new BubbleSort());   // Клиент выбирает
// Выбор управляется клиентом

Практическое правило выбора

Используй State когда:

  • Поведение объекта зависит от состояния
  • Переходы между состояниями определены
  • Состояния тесно связаны с логикой объекта

Используй Strategy когда:

  • Нужно выбирать алгоритм во время выполнения
  • Несколько независимых вариантов одной операции
  • Клиент должен выбирать способ выполнения

Резюме

State — объект сам меняет своё поведение при изменении внутреннего состояния. Strategy — клиент явно выбирает алгоритм для использования. State часто используется для моделирования жизненного цикла объекта, Strategy — для выбора алгоритма обработки. Оба используют полиморфизм, но с разной семантикой и целью.