В чем разница между шаблонами ООП Состояние и Стратегия?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Разница между паттернами 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);
Таблица сравнения
| Аспект | State | Strategy |
|---|---|---|
| Назначение | Изменение поведения при изменении состояния | Выбор алгоритма во время выполнения |
| Кто выбирает | Сам объект (автоматический переход) | Клиент (явный выбор) |
| Состояния | Тесно связаны, определяют друг друга | Независимы, параллельны |
| Пример | Торговый автомат, заказ, платёж | Сортировка, способ оплаты, шифрование |
| Переходы | Могут быть сложные, циклические | Обычно линейные или без переходов |
| Количество объектов | Обычно много состояний | Обычно несколько стратегий |
| Временная жизнь | Меняется часто во время жизни объекта | Установленная один раз или редко меняется |
Сравнение кода
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 — для выбора алгоритма обработки. Оба используют полиморфизм, но с разной семантикой и целью.