20241110 ◎

Strategy Pattern

I left GoF at my parent's house, and I cannot use the reference right now. What a shame.

The Strategy Pattern is a design pattern where we define a family of algorithms, encapsulate each one, and make them interchangeable at run time. By following the design pattern, we can separate each detailed implementation from other code including the client code, and new strategies can be added without modifying the existing one.

There are three components in this pattern.

Strategy in Python / Design Patterns

Strategy Design Pattern in Python

This design pattern is very popular, and the implementation should not vary that much.

from abc import ABC, abstractmethod


# Strategy Interface
class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount: float) -> None:
        raise NotImplementedError("pay() must be implemented")


# Concrete Strategy 1
class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number: str) -> None:
        self.card_number = card_number

    def pay(self, amount: float) -> None:
        print(f"Paid ${amount:.2f} using Credit Card {self.card_number}")


# Concrete Strategy 2
class PayPalPayment(PaymentStrategy):
    def __init__(self, email: str) -> None:
        self.email = email

    def pay(self, amount: float) -> None:
        print(f"Paid ${amount:.2f} using PayPal account {self.email}")


# Context
class PaymentContext:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def set_strategy(self, strategy: PaymentStrategy) -> None:
        self.strategy = strategy

    def execute_payment(self, amount: float) -> None:
        self.strategy.pay(amount)


# Usage
if __name__ == "__main__":
    # Paying with Credit Card
    context = PaymentContext(CreditCardPayment("1234-5678-9012-3456"))
    context.execute_payment(100.0)

    # Switching to PayPal
    # By calling `set_strategy`, teh behavior of the `Context` can be switched at runtime,
    # demonstrating the flexibility offered by the Strategy Pattern.
    paypal_payment = PayPalPayment("[email protected]")
    context.set_strategy(paypal_payment)
    context.execute_payment(50.0)

It was easy to understand in hindsight, but when I first read this pattern in GoF, I could not understand that. Once I'm forced to implement it in real scenarios, the knowledge makes sense, and now I can have it organized in my head.


Yogurt 500 Sandwiches 300 Pancake & sausage 250 Protein shake 150 Protein bar 150 Salad 550 Berries 200 Oats 200

Total 2300 kcal


MUST:

TODO:


index 20241109 20241111