Strategy vs State Pattern: Key Differences and When to Use Each
Strategy pattern lets you swap algorithms or behaviors dynamically by encapsulating them in separate classes, while the State pattern manages an object's internal state and changes its behavior when the state changes. Both use composition and polymorphism but differ in intent: Strategy focuses on interchangeable algorithms, and State focuses on state-driven behavior changes.Quick Comparison
This table summarizes the main differences between the Strategy and State patterns.
| Aspect | Strategy Pattern | State Pattern |
|---|---|---|
| Purpose | Encapsulate interchangeable algorithms or behaviors | Manage object behavior based on internal state changes |
| Focus | Algorithm selection | State-driven behavior |
| Context Role | Uses a strategy object to perform behavior | Holds a state object representing current state |
| Behavior Change | Behavior changes by swapping strategy | Behavior changes automatically when state changes |
| State Awareness | Context is unaware of strategy internals | Context and states are tightly coupled |
| Use Case Example | Sorting algorithms, payment methods | TCP connection states, vending machine states |
Key Differences
The Strategy pattern is designed to let a client choose from multiple algorithms or behaviors at runtime. It defines a family of algorithms, encapsulates each one, and makes them interchangeable. The context class holds a reference to a strategy object and delegates the behavior to it. The context is unaware of the details of the strategy, promoting loose coupling.
In contrast, the State pattern models an object's behavior as a set of states. Each state is a class that implements behavior specific to that state. The context maintains a reference to the current state and delegates requests to it. When the state changes, the context's behavior changes automatically without the client needing to know about the state transitions.
While both patterns use composition and polymorphism, the Strategy pattern focuses on selecting an algorithm independently of the object's state, whereas the State pattern tightly couples behavior to the object's internal state and manages transitions between states internally.
Code Comparison
Here is an example showing the Strategy pattern where a context uses different payment methods as strategies.
from abc import ABC, abstractmethod class PaymentStrategy(ABC): @abstractmethod def pay(self, amount: float) -> None: pass class CreditCardPayment(PaymentStrategy): def pay(self, amount: float) -> None: print(f"Paying {amount} using Credit Card.") class PayPalPayment(PaymentStrategy): def pay(self, amount: float) -> None: print(f"Paying {amount} using PayPal.") class ShoppingCart: def __init__(self, payment_strategy: PaymentStrategy): self.payment_strategy = payment_strategy def checkout(self, amount: float) -> None: self.payment_strategy.pay(amount) # Usage cart = ShoppingCart(CreditCardPayment()) cart.checkout(100.0) cart.payment_strategy = PayPalPayment() cart.checkout(200.0)
State Pattern Equivalent
This example shows the State pattern where a TCP connection changes behavior based on its state.
from abc import ABC, abstractmethod class TCPState(ABC): @abstractmethod def open(self, connection): pass @abstractmethod def close(self, connection): pass class ClosedState(TCPState): def open(self, connection): print("Opening connection.") connection.state = OpenState() def close(self, connection): print("Connection already closed.") class OpenState(TCPState): def open(self, connection): print("Connection already open.") def close(self, connection): print("Closing connection.") connection.state = ClosedState() class TCPConnection: def __init__(self): self.state = ClosedState() def open(self): self.state.open(self) def close(self): self.state.close(self) # Usage conn = TCPConnection() conn.open() conn.open() conn.close() conn.close()
When to Use Which
Choose Strategy when you want to select from multiple algorithms or behaviors dynamically and independently of an object's state. It is ideal when you want to swap or extend algorithms without changing the context.
Choose State when an object's behavior depends on its internal state and you want the object to change behavior automatically as its state changes. It is best when you need to model complex state transitions and encapsulate state-specific behavior.