🎯 Strategy Pattern

✅ What You’ll Learn

  • What the Strategy Pattern is
  • When and why to use it
  • How to implement it in Python
  • Benefits of using it
  • Common use cases

📘 What is the Strategy Pattern?

Strategy Pattern is a behavioral design pattern that lets you define a family of algorithms, put each of them in a separate class, and make their objects interchangeable.

It allows the behavior of a class to change at runtime without modifying its code.

🧠 When to Use It

Use the Strategy Pattern when:

  • You have multiple algorithms for a specific task.
  • You want to swap the algorithms at runtime.
  • You want to avoid massive if-else or switch-case statements.
  • You want to follow the Open/Closed Principle: open for extension, closed for modification.

📊 UML Diagram Description

Imagine you’re building a program that needs to sort data, and you want to:

  • Allow different sorting algorithms (BubbleSort, QuickSort, MergeSort…)
  • Choose or change the algorithm at runtime
  • Keep your sorting system extendable

This diagram shows how to organize your classes to achieve all of that.

classDiagram
    class Strategy {
        <<interface>>
        +do_algorithm(data)
    }

    class BubbleSortStrategy {
        +do_algorithm(data)
    }

    class QuickSortStrategy {
        +do_algorithm(data)
    }

    class Context {
        -strategy: Strategy
        +set_strategy(strategy: Strategy)
        +execute_strategy(data)
    }

    Strategy <|.. BubbleSortStrategy
    Strategy <|.. QuickSortStrategy
    Context --> Strategy

🧭 Diagram Breakdown

🧩 1. Strategy Interface (Abstraction)

  • This is the common interface or abstract base class.
  • It declares a method do_algorithm(data) that all concrete strategies must implement.
  • This abstraction allows different strategies to be interchangeable.

🧩 2. BubbleSortStrategy and QuickSortStrategy (Concrete Strategies)

  • These implement the Strategy interface.
  • Each provides a specific version of the do_algorithm() method.
  • Example: Bubble sort and quick sort are two ways to sort a list, and they’re swappable.

🧩 3. Context Class

  • Holds a reference to a Strategy object.
  • Delegates the algorithm execution to the Strategy via execute_strategy(data).
  • Can dynamically change the strategy using set_strategy().

Context depends on Strategy but doesn’t implement or extend it.

🛠️ 4. Implementation of Strategy Pattern in Python

Step 1: Define the Strategy Interface (using Abstract Base Class)

from abc import ABC, abstractmethod

class Strategy(ABC):
    @abstractmethod
    def do_algorithm(self, data):
        pass

Step 2: Implement Concrete Strategies

class BubbleSortStrategy(Strategy):
    def do_algorithm(self, data):
        print("Using Bubble Sort")
        return sorted(data)  # Simulating bubble sort for simplicity

class QuickSortStrategy(Strategy):
    def do_algorithm(self, data):
        print("Using Quick Sort")
        return sorted(data)  # Simulating quick sort for simplicity

Step 3: Create the Context

class Context:
    def __init__(self, strategy: Strategy):
        self._strategy = strategy

    def set_strategy(self, strategy: Strategy):
        self._strategy = strategy

    def execute_strategy(self, data):
        return self._strategy.do_algorithm(data)

Step 4: Use It

if __name__ == "__main__":
    data = [5, 3, 9, 1]

    context = Context(BubbleSortStrategy())
    print(context.execute_strategy(data))  # Using Bubble Sort

    context.set_strategy(QuickSortStrategy())
    print(context.execute_strategy(data))  # Using Quick Sort

✅ Output

Using Bubble Sort
[1, 3, 5, 9]
Using Quick Sort
[1, 3, 5, 9]

🚀 Benefits of Strategy Pattern

  • Flexibility: Swap algorithms without changing the context.
  • Clean Code: Avoid long if-else or switch statements.
  • Reusability: Strategies can be reused in different contexts.
  • Testability: You can test strategies in isolation.

🔥 Real-world Use Cases

  • Sorting algorithms (as above)
  • Payment methods (CreditCard, PayPal, ApplePay)
  • Compression strategies (Zip, Rar, Tar)
  • Pathfinding algorithms (Dijkstra, A*, BFS)
  • Game AI behaviors

📌 Advanced Tip: Use Functions as Strategies (Pythonic Way)

You can also use first-class functions as strategies:

def bubble_sort(data):
    print("Function Bubble Sort")
    return sorted(data)

def quick_sort(data):
    print("Function Quick Sort")
    return sorted(data)

class FunctionContext:
    def __init__(self, strategy_func):
        self._strategy_func = strategy_func

    def set_strategy(self, strategy_func):
        self._strategy_func = strategy_func

    def execute(self, data):
        return self._strategy_func(data)

ctx = FunctionContext(bubble_sort)
print(ctx.execute([3, 1, 4]))
ctx.set_strategy(quick_sort)
print(ctx.execute([3, 1, 4]))

📚 Summary

Component Role
Strategy Interface for algorithms
ConcreteStrategy Actual implementations
Context Uses the strategy