Strategy pattern

RoadmapsPython

Overview

The Strategy pattern lets you change how a piece of code works without changing the code itself. You do this by passing a function or an object (the "Strategy") that contains the rule you want to use. Imagine traveling to work. Your goal is always the same: reach the office. But your strategy changes. On a rainy day, you take a taxi. On a sunny day, you walk. You swap your strategy based on the situation. Here is a simple example in a shopping app. We want to calculate the final price after a discount: ```python # These are our strategies (rules) def no_discount(price): return price def student_discount(price): return price - 50 # This is our main code (context) def checkout(price, discount_strategy): # We call whichever strategy was passed in return discount_strategy(price) ``` Now we can swap the strategy when we check out: ```python # Using different strategies print(checkout(200, no_discount)) print(checkout(200, student_discount)) ``` Notice that the `checkout` function never changes. If we want to add a `festival_discount` tomorrow, we just write a new small function and pass it in. Let us practice. Here is a faded example. Fill in the blank to use the festival strategy. ```python def festival_discount(price): return price / 2 # Fill the blank to apply the festival discount final_price = checkout(500, ____) ``` The rule to remember: **The Strategy pattern lets you swap out the behavior of an object or function at runtime.** There is a sharp edge here. Every strategy must accept the exact same arguments. If `student_discount` suddenly needs a `student_id`, but `no_discount` does not, the `checkout` function will crash. All strategies must look exactly the same to the caller.

If you use many `if/elif` statements to handle different rules, your code becomes messy. The Strategy pattern splits each rule into its own small, clean function or class.

Where used: Payment processing (Credit Card vs UPI), Sorting lists (Alphabetical vs Date), Applying discounts

Why learn this

Code walkthrough

def uppercase_rule(text):
    return text.upper()

def lowercase_rule(text):
    return text.lower()

def format_text(text, rule):
    return rule(text)

result = format_text("Hello", uppercase_rule)
print(result)

Focus: return rule(text)

Aha moment

def add(a, b): return a + b
def multiply(a, b): return a * b

def calculate(x, y, math_strategy):
    return math_strategy(x, y)

# Passing the built-in 'max' function!
print(calculate(10, 20, max))

Prediction: What does this print? Look closely at the strategy being passed.

Common guess: It crashes or prints an error.

Any function that takes the correct number of arguments can be a strategy. Here, Python's built-in `max` function takes two numbers, so it works perfectly as our strategy!

Common mistakes

Recall questions

Understanding checks

What does this code print?

Mountain road

The `navigate` function receives the `scenic_route` function. It calls it and returns the result. The behavior was swapped without changing `navigate`.

A developer writes a sorting function and passes a `highest_first` rule to it. Why is this an example of the Strategy pattern?

Because the rule for sorting (the strategy) is passed in from the outside, allowing the sort behavior to change without rewriting the sort function.

The core sorting logic stays the same, but the comparison rule is swapped out at runtime.

Practice tasks

Swap the strategy

Given this code, change the `print` line so that it uses the `upi_payment` strategy instead of `cash_payment`.

Continue learning

Previous: Class Creation and Instantiation

Previous: Defining functions and return values

Return to Python Roadmap