Loading...
Loading...
Implements the Strategy pattern in Python backends. Run when the user mentions strategy pattern, or when you see or need a switch on type/method, multiple behaviors under the same contract, or interchangeable algorithms—apply this skill proactively without the user naming it.
npx skill4agent add progmichaelkibenko/top-coder-agent-skills strategy-pattern-pythonif method == "card": ... elif method == "paypal": ...| Role | Responsibility |
|---|---|
| Context | Holds a reference to one strategy; delegates the varying work to it; exposes a setter (or constructor) so clients can inject/replace the strategy. |
| Strategy (protocol/ABC) | Common contract for all strategies (e.g. single method like |
| Concrete strategies | Implement the protocol/ABC; each encapsulates one variant of the algorithm. |
| Client | Chooses a concrete strategy and passes it to the context (e.g. from request params, config, or factory). |
# One big class; every new payment method forces edits here.
class PaymentService:
def process_payment(self, amount: float, method: str, details: dict) -> dict:
if method == "stripe":
return self._stripe_charge(amount, details)
if method == "paypal":
return self._paypal_charge(amount, details)
if method == "bank":
return self._bank_transfer(amount, details)
raise ValueError("Unknown method")
def _stripe_charge(self, amount: float, details: dict) -> dict: ...
def _paypal_charge(self, amount: float, details: dict) -> dict: ...
def _bank_transfer(self, amount: float, details: dict) -> dict: ...# strategies/payment_strategy.py
from typing import Protocol, runtime_checkable
@runtime_checkable
class PaymentStrategy(Protocol):
def execute(self, amount: float, details: dict) -> dict:
"""Return dict with at least 'id' key."""
...# strategies/stripe_strategy.py
class StripeStrategy:
def execute(self, amount: float, details: dict) -> dict:
payment_intent = stripe.PaymentIntent.create(amount=amount, **details)
return {"id": payment_intent.id}
# strategies/paypal_strategy.py
class PaypalStrategy:
def execute(self, amount: float, details: dict) -> dict:
order = paypal_client.orders.create(amount=amount, **details)
return {"id": order.id}# services/payment_context.py
class PaymentContext:
def __init__(self, strategy: PaymentStrategy) -> None:
self._strategy = strategy
def set_strategy(self, strategy: PaymentStrategy) -> None:
self._strategy = strategy
def process_payment(self, amount: float, details: dict) -> dict:
return self._strategy.execute(amount, details)# routes/payments.py
strategies: dict[str, PaymentStrategy] = {
"stripe": StripeStrategy(),
"paypal": PaypalStrategy(),
}
context = PaymentContext(strategies["stripe"])
@router.post("/pay")
def pay(body: PayBody) -> dict:
strategy = strategies.get(body.method, strategies["stripe"])
context.set_strategy(strategy)
return context.process_payment(body.amount, body.details)typing.Protocolabc.ABCasync def execute(...)AsyncPaymentStrategystrategies/stripe_strategy.pystrategies/base.pystrategies/payment_strategy.py