Strategy Pattern¶
Category: Behavioral Pattern
Overview¶
Define a family of algorithms, encapsulate each one, and make them interchangeable. This pattern lets algorithms vary independently from clients that use them, enabling runtime selection of behavior without complex conditional logic.
Usage Guidelines¶
Use when:
- Multiple ways to perform an operation need to be chosen at runtime
- Code contains many conditionals that select behavior variants
- Related algorithms share a common interface but differ in implementation
- Algorithm implementation details should be isolated from client code
Avoid when:
- Only one way to perform the operation exists
- The algorithm is trivial and doesn't justify abstraction
- The behavior never changes or has no variants
- The indirection overhead is unacceptable for performance
Implementation¶
from abc import ABC, abstractmethod
# Strategy Interface
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> str:
pass
# Concrete Strategies
class CreditCardPayment(PaymentStrategy):
def __init__(self, card_number: str):
self.card_number = card_number
def pay(self, amount: float) -> str:
return f"Paid ${amount:.2f} using Credit Card ending in {self.card_number[-4:]}"
class PayPalPayment(PaymentStrategy):
def __init__(self, email: str):
self.email = email
def pay(self, amount: float) -> str:
return f"Paid ${amount:.2f} using PayPal account {self.email}"
class CryptocurrencyPayment(PaymentStrategy):
def __init__(self, wallet_address: str):
self.wallet_address = wallet_address
def pay(self, amount: float) -> str:
return f"Paid ${amount:.2f} using Crypto wallet {self.wallet_address[:10]}..."
# Context
class ShoppingCart:
def __init__(self):
self._items: list[float] = []
self._payment_strategy: PaymentStrategy | None = None
def add_item(self, price: float) -> None:
self._items.append(price)
def get_total(self) -> float:
return sum(self._items)
def set_payment_strategy(self, strategy: PaymentStrategy) -> None:
self._payment_strategy = strategy
def checkout(self) -> str:
if self._payment_strategy is None:
raise ValueError("Payment strategy not set")
total = self.get_total()
if total == 0:
return "Cart is empty"
return self._payment_strategy.pay(total)
Usage¶
# Create shopping cart
cart = ShoppingCart()
cart.add_item(100.00)
cart.add_item(50.00)
# Pay with credit card
cart.set_payment_strategy(CreditCardPayment("1234-5678-9012-3456"))
print(cart.checkout()) # Paid $150.00 using Credit Card ending in 3456
# Change strategy to PayPal
cart.set_payment_strategy(PayPalPayment("user@example.com"))
print(cart.checkout()) # Paid $150.00 using PayPal account user@example.com
# Change strategy to Cryptocurrency
cart.set_payment_strategy(CryptocurrencyPayment("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"))
print(cart.checkout()) # Paid $150.00 using Crypto wallet 0x742d35Cc...
Trade-offs¶
Benefits:
- Algorithms can be switched at runtime for flexibility
- New strategies can be added without modifying context (Open/Closed Principle)
- Eliminates complex conditional logic through clean object composition
- Each strategy can be tested independently
Drawbacks:
- Creates many strategy objects increasing class count
- Clients must understand different strategies to select appropriately
- Context and strategy must share data with communication overhead
- Overkill for simple algorithms that rarely change
Real-World Examples¶
- Sorting algorithms choosing between bubble sort, quick sort, merge sort
- Compression algorithm selection (ZIP, RAR, TAR)
- Route planning with different strategies (shortest, fastest, scenic)
- Authentication methods (OAuth, JWT, Basic Auth)
Related Patterns¶
- State
- Template Method
- Command
- Factory
API Reference¶
design_patterns.behavioral.strategy
¶
Strategy Pattern Module
The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. This pattern is useful when you have multiple ways to perform an operation and want to choose the appropriate one at runtime.
Example
Using different payment strategies:
BubbleSort
¶
Bases: SortStrategy
Bubble sort algorithm strategy.
Source code in src/design_patterns/behavioral/strategy.py
sort(data)
¶
Sort using bubble sort.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
list[int]
|
The list to sort. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The sorted list. |
Source code in src/design_patterns/behavioral/strategy.py
CreditCardPayment
¶
Bases: PaymentStrategy
Payment strategy using credit card.
Source code in src/design_patterns/behavioral/strategy.py
__init__(card_number)
¶
Initialize credit card payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
card_number
|
str
|
The credit card number. |
required |
pay(amount)
¶
Process credit card payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float
|
The amount to pay. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Payment confirmation message. |
Source code in src/design_patterns/behavioral/strategy.py
CryptocurrencyPayment
¶
Bases: PaymentStrategy
Payment strategy using cryptocurrency.
Source code in src/design_patterns/behavioral/strategy.py
__init__(wallet_address)
¶
Initialize cryptocurrency payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
wallet_address
|
str
|
The cryptocurrency wallet address. |
required |
pay(amount)
¶
Process cryptocurrency payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float
|
The amount to pay. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Payment confirmation message. |
Source code in src/design_patterns/behavioral/strategy.py
DataSorter
¶
Context class that uses different sorting strategies.
Source code in src/design_patterns/behavioral/strategy.py
__init__(strategy)
¶
Initialize with a sorting strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strategy
|
SortStrategy
|
The sorting strategy to use. |
required |
set_strategy(strategy)
¶
Change the sorting strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strategy
|
SortStrategy
|
The new sorting strategy. |
required |
sort_data(data)
¶
Sort data using the current strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
list[int]
|
The list to sort. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The sorted list. |
MergeSort
¶
Bases: SortStrategy
Merge sort algorithm strategy.
Source code in src/design_patterns/behavioral/strategy.py
sort(data)
¶
Sort using merge sort.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
list[int]
|
The list to sort. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The sorted list. |
Source code in src/design_patterns/behavioral/strategy.py
PayPalPayment
¶
Bases: PaymentStrategy
Payment strategy using PayPal.
Source code in src/design_patterns/behavioral/strategy.py
__init__(email)
¶
Initialize PayPal payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
email
|
str
|
The PayPal account email. |
required |
pay(amount)
¶
Process PayPal payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float
|
The amount to pay. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Payment confirmation message. |
PaymentStrategy
¶
Bases: ABC
Abstract base class for payment strategies.
Source code in src/design_patterns/behavioral/strategy.py
pay(amount)
abstractmethod
¶
Process a payment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float
|
The amount to pay. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A message indicating payment status. |
QuickSort
¶
Bases: SortStrategy
Quick sort algorithm strategy.
Source code in src/design_patterns/behavioral/strategy.py
sort(data)
¶
Sort using quick sort.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
list[int]
|
The list to sort. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The sorted list. |
Source code in src/design_patterns/behavioral/strategy.py
ShoppingCart
¶
Shopping cart that uses different payment strategies.
Source code in src/design_patterns/behavioral/strategy.py
__init__()
¶
add_item(price)
¶
Add an item to the cart.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
price
|
float
|
The price of the item. |
required |
checkout()
¶
Process the payment using the selected strategy.
Returns:
| Type | Description |
|---|---|
str
|
Payment confirmation message. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no payment strategy is set. |
Source code in src/design_patterns/behavioral/strategy.py
get_total()
¶
Calculate the total price of all items.
Returns:
| Type | Description |
|---|---|
float
|
The total price. |
set_payment_strategy(strategy)
¶
Set the payment strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strategy
|
PaymentStrategy
|
The payment strategy to use. |
required |
SortStrategy
¶
Bases: ABC
Abstract base class for sorting strategies.
Source code in src/design_patterns/behavioral/strategy.py
sort(data)
abstractmethod
¶
Sort the given data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
list[int]
|
The list of integers to sort. |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The sorted list. |