← Back to Python

All Topics

Advertisement

Learn/Python/Advanced Python

Behavioral Patterns - Strategy, Command, State

Topic: Design Patterns

Advertisement

Introduction

Behavioral design patterns are concerned with communication between objects, what goes on between objects, and how they operate together. These patterns help encapsulate processes and define communication mechanisms between objects.

Strategy Pattern

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable, allowing the algorithm to vary independently from clients that use it.

from abc import ABC, abstractmethod

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

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

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

class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append((item, price))
    
    def set_payment(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        total = sum(price for _, price in self.items)
        self.payment_strategy.pay(total)

cart = ShoppingCart()
cart.add_item("Book", 20)
cart.add_item("Pen", 5)
cart.set_payment(CreditCardPayment("1234-5678-9012-3456"))
cart.checkout()

Command Pattern

The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and support for undoable operations.

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass
    
    @abstractmethod
    def undo(self):
        pass

class Light:
    def on(self):
        print("Light is ON")
    
    def off(self):
        print("Light is OFF")

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.on()
    
    def undo(self):
        self.light.off()

class RemoteControl:
    def __init__(self):
        self.history = []
    
    def execute_command(self, command):
        command.execute()
        self.history.append(command)
    
    def undo_last(self):
        if self.history:
            self.history.pop().undo()

light = Light()
remote = RemoteControl()
remote.execute_command(LightOnCommand(light))
remote.undo_last()

State Pattern

The State pattern allows an object to alter its behavior when its internal state changes, making the object appear to change its class.

class State(ABC):
    @abstractmethod
    def insert_coin(self, machine):
        pass
    
    @abstractmethod
    def eject_coin(self, machine):
        pass
    
    @abstractmethod
    def press_button(self, machine):
        pass

class NoCoinState(State):
    def insert_coin(self, machine):
        print("Coin inserted")
        machine.set_state(machine.has_coin_state)
    
    def eject_coin(self, machine):
        print("No coin to eject")
    
    def press_button(self, machine):
        print("Insert coin first")

class HasCoinState(State):
    def insert_coin(self, machine):
        print("Coin already inserted")
    
    def eject_coin(self, machine):
        print("Coin returned")
        machine.set_state(machine.no_coin_state)
    
    def press_button(self, machine):
        print("Dispensing product")
        machine.set_state(machine.no_coin_state)

class VendingMachine:
    def __init__(self):
        self.no_coin_state = NoCoinState()
        self.has_coin_state = HasCoinState()
        self.current_state = self.no_coin_state
    
    def set_state(self, state):
        self.current_state = state
    
    def insert_coin(self):
        self.current_state.insert_coin(self)
    
    def press_button(self):
        self.current_state.press_button(self)

machine = VendingMachine()
machine.insert_coin()
machine.press_button()

Practice Problems

  1. Implement different sorting strategies (QuickSort, MergeSort, BubbleSort) with a strategy pattern.
  2. Create a command pattern for a text editor with undo/redo functionality.
  3. Build a state machine for a vending machine with different states.
  4. Implement a payment strategy system with multiple payment methods.
  5. Create a document state workflow (Draft, Review, Published) using the state pattern.

Advertisement

Advertisement

Need More Practice?

Get personalized Python help from ChatWhole's AI-powered platform.

Get Expert Help →