Menu
Coddy logo textTech

Strategy Pattern

Part of the Object Oriented Programming section of Coddy's Python journey — lesson 48 of 64.

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. You can switch algorithms at runtime without changing the client code.

Here are simple strategy classes for different payment methods:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

Each strategy implements the same method (pay) but with different behavior.

Create a context class that uses strategies:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

The context class can switch between different payment strategies.

Use the strategy pattern:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# Use credit card strategy
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# Switch to PayPal strategy
cart.set_payment_strategy(PayPal())
print(cart.checkout())

Create another example with sorting strategies:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

# Use different sorting strategies
numbers = [3, 1, 4, 1, 5]

sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))

sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))

Output:

Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]

Key Point: The Strategy Pattern lets you swap algorithms at runtime. Define different strategies with the same interface, then let the context class choose which one to use. This makes your code flexible and easy to extend with new algorithms without changing existing code.

challenge icon

Challenge

Medium

Implement a new BitcoinPayment strategy for our shopping system.

Your task is to:

  1. Create a BitcoinPayment class that implements PaymentStrategy
    • It should accept a wallet_address in the constructor
    • The pay method should print exactly: Paying $X using Bitcoin wallet: Y where X is the amount and Y is the wallet address
    • The pay method should return True after printing
  2. Write a main function that:
    • Creates a shopping cart
    • Adds a laptop costing $1200 and headphones costing $100 to the cart
    • Creates a BitcoinPayment with the wallet address "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    • Sets this payment strategy on the cart
    • Calls the checkout method

The starter code already includes if __name__ == "__main__": at the bottom — you do not need to add it yourself. This is a Python convention that ensures your main() function only runs when the file is executed directly (not when it is imported by another module). Simply define your main() function and the provided block will call it automatically.

Follow the same structure as shown in the lesson examples.

Cheat sheet

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. You can switch algorithms at runtime without changing the client code.

Create strategy classes with the same interface:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

Create a context class that uses strategies:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

Use the strategy pattern:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# Use credit card strategy
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# Switch to PayPal strategy
cart.set_payment_strategy(PayPal())
print(cart.checkout())

Another example with sorting strategies:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

Try it yourself

from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, expiry_date, cvv):
        self.card_number = card_number
        self.expiry_date = expiry_date
        self.cvv = cvv
        
    def pay(self, amount):
        print(f"Paying ${amount} using Credit Card: {self.card_number}")
        return True

class PayPalPayment(PaymentStrategy):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        
    def pay(self, amount):
        print(f"Paying ${amount} using PayPal account: {self.email}")
        return True

class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append({"item": item, "price": price})
    
    def set_payment_strategy(self, payment_strategy):
        self.payment_strategy = payment_strategy
    
    def checkout(self):
        total = sum(item["price"] for item in self.items)
        if self.payment_strategy:
            return self.payment_strategy.pay(total)
        else:
            raise ValueError("No payment strategy set")

# Create your BitcoinPayment strategy class here


if __name__ == "__main__":
    main()
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming