How to Implement the Strategy Design Pattern in Python: A Step-by-Step Guide

Understanding the Strategy Pattern in Python

Imagine you're at an online checkout. You see buttons for Credit Card, PayPal, and Crypto. You pick one, and the system handles the payment differently for each, but the checkout flow itself doesn't change.

The Strategy Pattern is exactly this: a way to define a family of algorithms (payment methods, sorting techniques, export formats), make them interchangeable, and let the client (the checkout process) use any one of them without knowing the details.

Try It: The Navigation System

The NavigationSystem (Context) is the same, but the Strategy changes how the route is calculated.

Context

NavigationSystem

Current Strategy:

None Selected
Choose Strategy

Core Idea: Interchangeable Algorithms

The key is decoupling. You create a common, simple interface (e.g., a pay() method) that all your strategies must implement. The client code holds a reference to an object that follows this interface—it doesn't care which strategy it is, only that it can call pay().

This means you can swap strategies at runtime simply by assigning a different object, just like you did in the interactive example above!

Common Misconception: It's just a fancy name for If-Else

❌ The If-Else Trap

Many beginners think: "I can just use an if/elif/else block." This works for a couple of fixed options, but it doesn't scale. Every time you add a new behavior, you must open and modify the client class. This violates the Open/Closed Principle.

✅ The Strategy Solution

With Strategy, you add a new strategy class without touching the client. The client remains stable and closed for modification, while the system remains open for extension.

(Advanced) When to Prefer Inheritance Instead

If you have one, unchanging behavior that will never have alternatives, subclassing the context directly is simpler. For example, a Square class that always calculates area as side * side doesn't need a CalculateAreaStrategy.

Inheritance is clearer when the variation is horizontal (a kind of thing) and not behavioral (a way of doing thing). Use Strategy when you anticipate multiple, swappable implementations of a single responsibility.

Design Patterns Tutorial: Strategy Pattern Overview

Where does Strategy fit in the big picture?

In the vast world of Design Patterns, the Strategy Pattern belongs to the Behavioral family.

While Creational patterns handle object creation and Structural patterns handle object composition, Behavioral patterns are all about how objects interact and communicate. Strategy specifically addresses the assignment of responsibilities: it lets you extract a varying behavior into its own object, so the main context object can simply delegate to it.

Intuition: The Toolbox Analogy

Think of the Context as your hand. The strategies are tools in a toolbox. Your hand doesn't change; it just holds whatever tool you need for the job.

Context (Hand)
🖐️

Holding Tool:

Empty Hand
Select Tool

Key Benefits: Runtime Flexibility

The two superpowers of Strategy are Runtime Flexibility and avoiding Conditional Logic.

  • Runtime Flexibility: You can swap the behavior while your program is running. Imagine a video game where an enemy's AI strategy changes from Aggressive to Defensive based on health—you just assign a new strategy object.
  • Avoiding Conditionals: Instead of a growing if/elif/else chain, you use polymorphism. This makes your code cleaner, more maintainable, and easier to test.

⚠️ Common Misconception: "Is this too complex?"

Yes, Strategy introduces extra classes. For a tiny, unchanging set of behaviors (e.g., exactly two payment options that will never grow), a simple if statement is perfectly fine.

The pattern shines when you have three or more behaviors, or when you expect to add new behaviors in the future. Ask yourself: "Is this conditional logic likely to grow?" If yes, Strategy is worth the slight initial overhead.

(Advanced) Interaction with the Factory Pattern

The Context class holds a reference to a Strategy object, but how does it get that object? Often, the strategy is injected from outside. This is where the Factory Pattern can complement Strategy.

A StrategyFactory can encapsulate the creation logic, deciding which concrete strategy to instantiate based on configuration or user input. This keeps the Context completely decoupled from strategy creation.

factory_integration.py
# Context uses a Factory to obtain strategies
class NavigationSystem:
    def __init__(self, strategy_factory):
        self._strategy_factory = strategy_factory
        self._strategy = None

    def set_route_type(self, route_type):
        # Factory creates the appropriate strategy
        self._strategy = self._strategy_factory.create_strategy(route_type)

    def calculate_route(self, start, end):
        return self._strategy.compute_route(start, end)

# Simple Factory
class RouteStrategyFactory:
    def create_strategy(self, route_type):
        if route_type == "driving":
            return DrivingStrategy()
        elif route_type == "walking":
            return WalkingStrategy()
        # ... add new strategies without changing NavigationSystem

Composition Over Inheritance Example

Let's get practical. We've talked about the Strategy pattern, but why do we say "Composition over Inheritance"?

The classic example is building a Car.

If you use Inheritance, you might create a class hierarchy: SportsCar, ElectricCar, HybridSportsCar. Before you know it, your class tree looks like a tangled mess of branches.

If you use Composition, you build a generic Car class that simply has an Engine. You can swap the engine at runtime without creating new car classes.

Try It: The Modular Car Builder

Notice how the Car (Context) stays the same. We simply compose it with different Engine strategies.

Context (Car)
🚗

Current Engine:

None Installed
Select Engine to Compose

Why Composition Wins: Loose Coupling

The magic here is decoupling. The Car class doesn't need to know how an engine works. It just knows the interface: start() and drive().

This is Loose Coupling. If you invent a Fusion Engine tomorrow, you just write a new FusionEngine class. You don't have to touch the Car class, and you don't have to rewrite the whole inheritance tree.

❌ The Inheritance Trap

If you used inheritance, adding a new engine type might force you to create SportsCarWithV8, SportsCarWithElectric, etc.

This is called the Combinatorial Explosion. Your classes become rigid and hard to maintain.

✅ The Composition Solution

With composition, you have One Car Class and N Engine Classes.

This scales infinitely. You can even swap engines while the car is running (in code terms: at runtime).

Misconception: "Inheritance is for Code Reuse"

Beginners often say: "But inheritance lets me reuse code!"
Yes, it does. But it also forces you to inherit dependencies. This is known as the Fragile Base Class problem. If the parent class changes its internal logic, it might break all the subclasses that rely on it, even if they don't use that specific logic.

Composition allows you to reuse behavior (via the Strategy interface) without inheriting the implementation details or state of the parent.

(Advanced) When Inheritance is Still Okay

Don't throw inheritance in the trash! It is still the best tool for Is-A relationships where the hierarchy is stable.

For example, in a GUI library, a Button is a Widget. They share common state (position, size) and base behaviors (drawing to screen). Here, inheritance is cleaner than composition because a Button is fundamentally a Widget, not just a Widget that has Widget behavior.

Strategy in Python: Functions, Classes, and Protocols

Now that we understand the concept, let's look at how the Strategy Pattern actually lives inside the Python ecosystem. Python is special because it treats functions as first-class citizens. This means we have two ways to implement a Strategy: the Functional Way (simple) and the Class-Based Way (robust).

Visualizing the Decision: Function vs. Class

In Python, you often ask: "Do I need a full class for this behavior?"
Select an approach below to see how the Context interacts with the Strategy.

Context

DataExporter

Current Implementation:

Waiting for input...
Choose Approach

How Strategy Fits in the Pattern Family

The Strategy Pattern is a Behavioral pattern. It's all about how objects interact and assign responsibilities. But how is it different from its cousins?

Strategy

Goal: Swap algorithms.
"I need to sort this list, but I want to choose between QuickSort or MergeSort at runtime."

Decorator

Goal: Add behavior.
"I have a text object, but I want to wrap it to add bold formatting and caching."

Adapter

Goal: Make things fit.
"This legacy library returns XML, but my app needs JSON. I'll wrap it."

Misconception: "Python's Dynamism Makes Strategy Unnecessary"

A common thought among Pythonists is: "Why create a whole class hierarchy? I can just pass a lambda function!"

You are absolutely right—Python allows this! But the explicit Strategy Pattern (using classes) still wins in professional settings for three reasons:

  • Clarity & Intent: A PaymentStrategy class with a pay() method is self-documenting. A complex lambda is often a "black box."
  • Stateful Strategies: If your algorithm needs to remember things (like a discount counter or a cache), a class is much cleaner than passing mutable default arguments or closures around.
  • Tooling & Type Hints: As we'll see next, classes play much nicer with modern IDEs and type checkers (like mypy).

(Advanced) Strategy with Type Hints and Protocols

Python is dynamically typed, but modern Python (3.8+) has a powerful feature called Protocol. This allows you to define an interface without forcing inheritance.

This gives you the "Duck Typing" flexibility of Python ("if it walks like a duck...") but with the safety of static analysis.

protocol_example.py
# Define the contract (Interface)
from typing import Protocol, runtime_checkable

@runtime_checkable
class ExportStrategy(Protocol):
    def __call__(self, data: dict) -> str: ...

# Context uses the Protocol
def export_data(data: dict, strategy: ExportStrategy) -> str:
    return strategy(data)

# Implementation (Matches Protocol automatically)
def csv_exporter(data: dict) -> str:
    return ",".join(data.keys())

# Static type checkers (mypy) will now verify correctness!
export_data({"a": 1}, csv_exporter)  # ✅ OK
export_data({"a": 1}, 42)            # ❌ Error: int is not a strategy

By using Protocol, you get the best of both worlds: the loose coupling of the Strategy pattern and the safety of strict typing.

Behavioral Design Patterns: Strategy Pattern

Let's zoom out. We've seen how to swap behaviors, but where does the Strategy Pattern actually fit in the grand architecture of software design?

Think of the Strategy Pattern like a Universal Plug Adapter. The device (your Context) stays the same—it has a standard socket. But you can plug in any adapter (Strategy) to match the wall outlet (the varying behavior). You don't rewire the device; you just swap the plug.

Visualizing the Concept: The Universal Socket

The Context (Device) has a fixed interface. The Strategy (Adapter) changes how it connects to the world.

Context (Device)
Device Logic
Socket
Standard
Swap Adapter

This is the essence of a behavioral design pattern: it's about how objects behave and interact, not how they're created or structured. Strategy specifically encapsulates an algorithm into its own object, letting the context delegate to it.

Misconception: All behavioral patterns are interchangeable

A common beginner mistake is thinking all behavioral patterns solve the same problem: "They all change behavior, right?" Not exactly. Each has a unique responsibility.

Strategy

Goal: Choose an algorithm.
"I need to sort this list. Should I use QuickSort or MergeSort?"

State

Goal: Change behavior based on internal state.
"The traffic light is Red, so I stop. It turns Green, so I go."

Observer

Goal: Subscribe to changes.
"When the data updates, notify all the charts."

Command

Goal: Encapsulate a request.
"Save this command to the history log so I can Undo later."

Real-world scenario: Sorting Algorithms

A classic example is a sorting utility that might need to use different algorithms based on data size or user preference.

Try It: Visualizing the Strategy Swap

The Sorter (Context) is the same. The Strategy determines the sorting logic.

Context (Sorter)

Current Algorithm:

None Selected
Select Strategy

Here, Sorter never knows how sorting happens—it just delegates. Want to add MergeSort? Write a new class; Sorter remains untouched. This avoids a tangled if algorithm == "quick": ... block.

(Advanced) Interaction with State Pattern

The State pattern and Strategy pattern look similar—both use composition and delegate to another object. But their intent differs:

  • Strategy: Lets you manually swap algorithms at any time (e.g., user selects a payment method).
  • State: Automatically changes behavior based on the context's internal state (e.g., a TrafficLight cycles through Red, Green, Yellow states without external intervention).

💡 They can work together!

A context might use State to manage its high-level state, and within each state, it could employ different Strategies for subtasks.

Example: A MediaPlayer has states (Playing, Paused). Each state might use a different BufferStrategy to handle data buffering.

In this hybrid approach, State manages the lifecycle (when to switch), while Strategy provides the variable behavior within each state. This gives you both automatic state transitions and flexible, swappable sub-algorithms.

Implementing the Strategy Pattern in Python

Let's get our hands dirty. We've seen the theory, but how does the Strategy Pattern actually look in Python? We'll build a sorting utility that can swap algorithms at runtime.

Step 1: Define the Contract (Interface)

The first rule of the Strategy Pattern is the Interface. It's a promise: "Whatever strategy you are, you must have a sort() method."

In Python, we enforce this using abc.ABC. This prevents us from accidentally creating a strategy that does nothing.

strategies.py
# 1. The Interface
from abc import ABC, abstractmethod

class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data: list) -> list:
        """Return a sorted copy of the data."""
        pass

Step 2: Create Concrete Strategies

Now we build the actual workers. Notice how FastSort and SlowSort are completely independent. They don't know about each other.

⚡ FastSort (Built-in)

class FastSort(SortStrategy):
    def sort(self, data):
        # Highly optimized C implementation
        return sorted(data)

🐌 SlowSort (Bubble)

class SlowSort(SortStrategy):
    def sort(self, data):
        # Deliberately inefficient
        arr = data.copy()
        for i in range(len(arr)):
            for j in range(0, len(arr) - i - 1):
                if arr[j] > arr[j + 1]:
                    arr[j], arr[j + 1] = arr[j + 1], arr[j]
        return arr

Try It: Injecting Strategies at Runtime

The Sorter (Context) holds a reference to a strategy. We can swap this reference anytime.

Context (Sorter)

Currently Using:

None

Data to Sort:

[5, 2, 8, 1, 9, 3]
Inject Strategy

The Context Code

Here is the Sorter class. It doesn't know how to sort; it just delegates to the strategy it holds.

class Sorter:
    def __init__(self, strategy: SortStrategy):
        self._strategy = strategy

    def set_strategy(self, strategy: SortStrategy) -> None:
        # Swap at runtime!
        self._strategy = strategy

    def execute(self, data: list) -> list:
        return self._strategy.sort(data)

Misconception: "One Strategy Per Algorithm is Enough"

Beginners often think: "If I have QuickSort, I just need one QuickSort class."

But what if you want Randomized QuickSort vs. Standard QuickSort?

Option A (Parameters): One class, but with a configuration flag.
Option B (Strategies): Two separate classes: QuickSortRandomPivot and QuickSortFirstPivot.

💡 Professor's Rule of Thumb

If the variation changes the core logic or is complex enough to need its own tests, make it a separate class (Option B). If it's just a simple number (like a threshold), a parameter (Option A) is fine.

(Advanced) Dependency Injection & Testing

The biggest benefit of this structure is Testability. Because the Context doesn't create the Strategy, we can inject a fake one during testing.

This is called Dependency Injection. Instead of running a real sort (which might be slow or complex), we inject a MockSort that always returns the same result.

test_sorter.py
# A Fake Strategy for testing
class MockSort(SortStrategy):
    def sort(self, data: list) -> list:
        return [1, 2, 3]  # Always returns this

# Test Logic
def test_sorter_uses_strategy():
    sorter = Sorter(MockSort())
    result = sorter.execute([5, 2, 8])
    assert result == [1, 2, 3]  # ✅ Passes instantly

This proves that your Sorter is correctly delegating to its strategy, without actually needing to sort anything.

Step-by-Step Implementation Guide

Welcome back! Now that we understand the theory, let's get our hands dirty. We're going to build a robust Strategy Pattern implementation from scratch.

Before writing a single line of logic, we need a clean home for our code. Organization is the first step to professional software engineering.

1. Setting up the Project Structure

Imagine you're building a house. You don't throw the bricks, paint, and furniture into one giant pile in the living room. You organize them!

We will create a dedicated package (folder) called strategies. This keeps your main application logic clean and separates the "what" (business logic) from the "how" (strategies).

Your File Tree

your_project/
├── main.py                  # Your application entry point
└── strategies/              # <-- The Strategy Package
    ├── __init__.py          # Makes 'strategies' a Python package
    ├── payment.py           # Contains: CreditCardStrategy, PayPalStrategy
    ├── sorting.py           # Contains: QuickSort, BubbleSort
    └── export.py            # Contains: CsvExportStrategy, JsonExportStrategy

Why this matters: When you have ten different strategies, a single folder becomes a clear, maintainable location. Your main code imports from strategies.payment instead of hunting through a monolithic file.

2. Defining the Context Class

The Context is the class that uses a strategy. Its only job is to hold a reference to a strategy object and delegate the varying behavior to it.

Think of the Context as a Universal Remote Control. The remote has a "Power" button. It doesn't know or care whether it's controlling a TV, a Soundbar, or an Air Conditioner—it just sends the same "Power" signal to whatever device is currently paired.

Try It: The Universal Remote

The Remote (Context) stays the same. We can swap the Target Device (Strategy) at runtime.

Context (Remote)

Paired Device:

None
Pair Device (Strategy)

Key Points of the Context

  • The Constructor: The __init__ method accepts any object that conforms to the strategy interface.
  • No If/Else: The context never checks if type(strategy) is TVStrategy. It just calls self._strategy.power() and trusts the object to handle it.
  • Delegation: This single line self._strategy.power() is the heart of the pattern. The Context orchestrates, the Strategy executes.

Common Pitfall: Forgetting set_strategy

A frequent beginner mistake is making the strategy immutable after construction. If you don't provide a way to swap it, you lose the runtime flexibility that makes Strategy useful.

❌ The Immutable Trap

def __init__(self, strategy):
    self._strategy = strategy
    # No way to change it later!

This forces you to create a new Context object every time you want to switch behaviors. It's rigid and clunky.

✅ The Dynamic Solution

def set_strategy(self, strategy):
    self._strategy = strategy
    # Just reassign the instance variable!

This is all it takes! You can swap strategies on the fly, just like pairing a different device to your remote.

Benefits of Loose Coupling

By keeping the Context and Strategy separate, we gain several superpowers:

  • Testability: In a unit test, you can give the Context a MockStrategy that just records if a method was called, without doing the real work.
  • Extensibility: Add a new strategy next month? Just write the new class. The Context code stays untouched.
  • Readability: Someone reading the Context sees it's about orchestrating logic, not implementing it. The "how" lives elsewhere.

(Advanced) Using Metaclasses for Auto-Registration

In very large projects, you might want strategies to self-register when they are defined. This avoids manually maintaining a list like {"credit_card": CreditCardStrategy}.

A Metaclass can automate this. It runs code whenever a new class is created.

registry.py
class StrategyMeta(type):
    registry = {}  # Class-level dict

    def __new__(mcs, name, bases, attrs):
        cls = super().__new__(mcs, name, bases, attrs)
        # If the class defines a 'strategy_name', auto-register it
        if hasattr(cls, 'strategy_name'):
            mcs.registry[cls.strategy_name] = cls
        return cls

class PaymentStrategy(ABC, metaclass=StrategyMeta):
    strategy_name = None
    @abstractmethod
    def pay(self, amount): ...

class CreditCardStrategy(PaymentStrategy):
    strategy_name = "credit_card"
    def pay(self, amount): ...

# Now all strategies are available in StrategyMeta.registry!

⚠️ Professor's Warning

Metaclasses add significant complexity. Only use this if you truly need automatic discovery (e.g., a plugin system where users upload new strategy files). For most applications, a simple manual mapping or configuration file is clearer and easier to debug.

Common Pitfalls and How to Avoid Them

You've learned the pattern, you've built the classes, and you're ready to ship. But before you do, let's talk about the traps. Even experienced developers fall into these.

The Strategy Pattern is powerful, but like any tool, it has a "sweet spot." Use it outside of that zone, and you risk making your code harder to maintain, not easier.

Pitfall 1: Over‑engineering with too many strategy classes

The Strategy Pattern adds a layer of indirection. You create an interface, separate classes for each behavior, and a context that delegates. This is fantastic when you have multiple, swappable algorithms that might change or grow.

But if you only have one or two simple, unchanging behaviors, that indirection becomes unnecessary noise.

Visualizing the Cost: Simple vs. Complex

Imagine you need to format text as either Plain Text or HTML. These formats will never change.
Click the buttons to see how much code you write for each approach.

Context (Report)

Current Approach:

Select an Approach
Waiting for selection...
Choose Implementation

Technical Reasoning: The Open/Closed Principle (open for extension, closed for modification) is the main reason to use Strategy. Ask: "Will I need to add new behaviors without changing existing code?" If the answer is no, stick with a simpler approach. Over‑engineering makes your codebase harder to navigate—new developers must understand the pattern's scaffolding even for trivial cases.

Pitfall 2: Not handling stateful strategies properly

A strategy object can hold internal state (e.g., a DiscountStrategy that tracks how many times it's been used). If you reuse the same instance of a stateful strategy across multiple context objects, they'll share that state unexpectedly.

The "Shared Hammer" Problem

Imagine two workers (Contexts) sharing one physical hammer (Strategy). If Worker A dents the hammer, Worker B is also affected.
Click "Work" to see how shared state causes bugs.

Strategy (Shared)
🔨

Internal Counter:

0
Worker Contexts
⚠️ The Bug

Notice how the counter keeps increasing globally? Worker B sees Worker A's work. This is usually not what you want unless the strategy is specifically designed to be a shared singleton.

The Fix: Create a new strategy instance for each context, or ensure the strategy is stateless. If you must share a stateful strategy (e.g., a caching strategy), document it clearly and consider using locks if concurrency is involved.

Pitfall 3: Ignoring type safety in Python strategy implementations

Python's duck typing is flexible, but in a large codebase, you want early error detection. If a strategy is missing the required method, you'll only find out at runtime—maybe in production.

Type hints and Protocol shift that error to development time, acting as in‑code documentation and enabling IDE autocomplete.

protocol_example.py
# Define the contract (Interface)
from typing import Protocol

class ExportStrategy(Protocol):
    def __call__(self, data: dict) -> str: ...

# Context uses the Protocol
class Exporter:
    def __init__(self, strategy: ExportStrategy):
        self._strategy = strategy
    def export(self, data: dict) -> str:
        return self._strategy(data)

# Type checker (mypy) will flag this:
exporter = Exporter(42)  # ❌ Error: 42 is not callable

Misconception: The pattern works without any testing

Because each strategy is a small, isolated class or function, it's easy to test. But beginners often think: "It's just one method—why test it?"

The reality: bugs in a strategy break the entire context. Since the context delegates, a faulty strategy produces incorrect results with no fallback.

Test the Strategy

Verify the strategy's output for various inputs.

def test_strategy():
    strategy = MyStrategy()
    result = strategy.process(10)
    assert result == 20

Test the Context

Mock the strategy and verify the context calls it correctly.

def test_context():
    mock = Mock()
    ctx = Context(mock)
    ctx.run()
    mock.process.assert_called()

(Advanced) Handling concurrency with strategy objects

If your application uses multiple threads (e.g., a web server handling requests), and you share a stateful strategy instance across threads, you can get race conditions.

Strategies are typically short‑lived and used within a single request. The safest approach is to avoid shared mutable state in strategies. Make strategies stateless, or create a new instance per context (which is usually per request).

💡 Rule of Thumb

In concurrent environments, treat strategies like functions—no side effects, no shared mutable state. If you need shared state, manage it explicitly with locks or thread‑local storage.

Frequently Asked Questions

Welcome to the FAQ Corner. Even experienced developers stumble on the nuances of design patterns. Let's tackle the most common questions about the Strategy Pattern, from "Why not just use if/else?" to handling Python-specific quirks.

Q1: Why not just use an if/else statement?

Imagine you are building a checkout system. You have Payment Methods.
Approach A (If/Else): You write one giant function that checks every single payment type. Every time you add a new payment (e.g., "Crypto"), you have to open that giant function and modify it.
Approach B (Strategy): You create a separate class for each payment. The checkout process just says "Pay me," and the strategy handles the rest.

Click the buttons to see the difference in code maintenance.

Context (Checkout)

Current Implementation Size:

Small

Code Complexity:

Choose Architecture

Q2: Why am I getting an AttributeError?

This is the most common beginner error. You passed a Class instead of an Instance, or the method name is wrong.
Click "Run Code" to see the error, then click "Apply Fix" to resolve it.

Code Editor
class Context:
def __init__(self, strategy):
self.strategy = strategy
self.strategy.pay(100)
# ...

Current State:

❌ AttributeError
Common Mistakes
❌ Passing Class:
Context(CreditCardStrategy)
✅ Passing Instance:
Context(CreditCardStrategy())
✅ Method Name:
Ensure pay() exists in the strategy.

Q3: Functions vs. Classes (Python Specifics)

In Python, you don't *always* need a class. If your strategy is just a simple calculation without state, a function is often cleaner.

When to use a Function

Use when: The logic is stateless (no memory of previous calls).

# Simple Function Strategy
def discount_strategy(price):
    return price * 0.9

When to use a Class

Use when: You need to track state (e.g., "how many times has this discount been used?") or you want clear, self-documenting code.

class DiscountStrategy:
    def __init__(self):
        self.usage_count = 0
        
    def apply(self, price):
        self.usage_count += 1
        return price * 0.9

Q4: Can I combine multiple strategies?

Absolutely! A context can hold references to multiple strategies. This is common in pipelines (e.g., a Validator strategy followed by a Processor strategy).

class PaymentProcessor:
    def __init__(self, validator, payment):
        self._validator = validator
        self._payment = payment

    def process(self, amount, card):
        # Chain strategies
        if self._validator.validate(card):
            self._payment.pay(amount)

Q5: Performance & GUI Considerations

Performance: The overhead of Strategy in Python is negligible (microseconds). The cost of an extra method call is far less than the cost of the algorithm itself (like sorting data).

GUI: Strategy is perfect for GUIs. A button (Context) can swap its "Action" (Strategy) at runtime without subclassing the button widget.

Post a Comment

Previous Post Next Post