Skip to main content
Design Patterns – Complete Beginner to Advanced Guide
CHAPTER 14 Intermediate

Strategy Pattern

Updated: May 16, 2026
30 min read

# CHAPTER 14

Strategy Pattern

1. Introduction

Imagine you are building a Google Maps clone. Initially, your app only calculates routes for Cars. Your calculateRoute() method works perfectly. A month later, you add Walking routes. You add an if statement. Then you add Bicycles. Then Public Transit. Your calculateRoute() method is now a terrifying, 2,000-line monster of nested if/else statements. If a developer breaks the Bicycle logic, the entire routing system crashes. This violates the Open/Closed Principle entirely. The Strategy Pattern is the architectural cure for algorithmic bloat. In this chapter, we will master the Strategy Pattern, learning how to extract dynamic algorithms into interchangeable classes, allowing our objects to swap behaviors instantly at runtime.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Identify the algorithmic bloat caused by massive switch or if/else statements.
  • Define the intent and structure of the Strategy Pattern.
  • Encapsulate families of algorithms into interchangeable Strategy classes.
  • Understand how to swap object behavior dynamically at runtime (Context switching).
  • Compare the Strategy Pattern with the State Pattern.

3. The Core Concept

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
  • The Context: The main object the user interacts with (e.g., the Navigator class).
  • The Strategy Interface: The contract that all algorithms must follow (e.g., RouteStrategy interface with a buildRoute() method).
  • The Concrete Strategies: The encapsulated algorithms (e.g., CarStrategy, BikeStrategy).

4. Swapping at Runtime

The magic of the Strategy pattern is dynamic behavior. Instead of hardcoding the algorithm inside the Navigator, the Navigator holds a reference to a RouteStrategy object. When the user clicks the "Bicycle" icon, the app calls $navigator->setStrategy(new BikeStrategy()). The Navigator doesn't know *how* the bike route is calculated; it just delegates the work to the currently active strategy.

5. Strategy vs. Decorator

They both use composition, but have different intents.
  • Decorator: *Adds* behavior to an object, wrapping it in new features.
  • Strategy: *Changes* the gut behavior of an object by swapping out its core algorithm.

6. UML Diagram

*Strategy Structure*
text
12345678
[ Context ] ---------------------> [ <<Interface>> Strategy ]
- strategy: Strategy                      + execute()
+ setStrategy(Strategy)                        ^
+ doAction() { strategy->execute() }           | (Implements)
                                   -------------------------
                                   |                       |
                       [ ConcreteStrategyA ]   [ ConcreteStrategyB ]
                         + execute()             + execute()

7. Code Example (PHP)

Let's build a dynamic Payment Processing system.
php
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
<?php
// --- 1. The Strategy Interface ---
interface PaymentStrategy {
    public function pay($amount);
}

// --- 2. Concrete Strategies (The Algorithms) ---
class CreditCardPayment implements PaymentStrategy {
    public function pay($amount) {
        echo "Processing $amount using Stripe Credit Card API.\n";
    }
}

class PayPalPayment implements PaymentStrategy {
    public function pay($amount) {
        echo "Processing $amount by redirecting to PayPal OAuth.\n";
    }
}

class CryptoPayment implements PaymentStrategy {
    public function pay($amount) {
        echo "Processing $amount via Ethereum Blockchain transaction.\n";
    }
}

// --- 3. The Context (The Shopping Cart) ---
class ShoppingCart {
    private $paymentStrategy;

    // We can set a default strategy, or inject one
    public function setPaymentStrategy(PaymentStrategy $strategy) {
        $this->paymentStrategy = $strategy;
    }

    public function checkout($total) {
        if (!$this->paymentStrategy) {
            throw new Exception("Please select a payment method.");
        }
        // The Context delegates the work to the dynamic strategy!
        $this->paymentStrategy->pay($total);
    }
}

// --- 4. Client Code ---
$cart = new ShoppingCart();

// User selects Credit Card
echo "User clicked Credit Card:\n";
$cart->setPaymentStrategy(new CreditCardPayment());
$cart->checkout(100); 

// User changes mind, selects PayPal (Dynamic Runtime Swapping!)
echo "\nUser clicked PayPal instead:\n";
$cart->setPaymentStrategy(new PayPalPayment());
$cart->checkout(100);
?>

8. Best Practices

  • Eliminate Switch Statements: The ultimate "code smell" indicating you need a Strategy Pattern is a massive switch statement based on a type variable (e.g., switch ($type) { case 'A': doA(); case 'B': doB(); }). Replace the switch statement by making A and B separate Strategy classes.

9. Common Mistakes

  • Over-Engineering Trivial Logic: If you have an if/else statement that calculates a 5% tax vs a 10% tax, do not create a FivePercentTaxStrategy class. The Strategy pattern introduces multiple new files and interfaces. It should only be used when the algorithms are complex, highly volatile, and require complete decoupling.

10. Mini Project: Build an Image Compression Tool

  1. 1. Context: Create an ImageSaver class.
  1. 2. Strategy: Create a CompressionStrategy interface with a compress($file) method.
  1. 3. Concrete Strategies: Create JpegCompression (lossy) and PngCompression (lossless).
  1. 4. Action: Write a script that loads an image, sets the Strategy to Jpeg, saves it, then dynamically swaps the strategy to Png and saves it again.

11. Practice Exercises

  1. 1. Define the primary architectural code smell (hint: large control structures) that indicates a codebase desperately needs to be refactored using the Strategy pattern.
  1. 2. Explain how the Strategy pattern enables an application to change its core behavior dynamically at runtime without requiring a reboot or a new object instantiation.

12. MCQs with Answers

Question 1

A developer is tasked with building a sorting module that needs to switch between QuickSort, MergeSort, and BubbleSort depending on the size of the array. To avoid a massive if/else block and adhere to the Open/Closed Principle, which pattern should they deploy to encapsulate these algorithms?

Question 2

In the Strategy Pattern, the class that holds the reference to the active algorithm and delegates the execution to it (e.g., the ShoppingCart class) is formally known as the:

13. Interview Questions

  • Q: Compare and contrast the Strategy Pattern with the State Pattern. Structurally they are nearly identical; how do their architectural intents differ?
  • Q: Walk me through a refactoring process. You inherit a massive 3,000-line class with a switch statement that handles 10 different types of data export (CSV, XML, JSON). Explain exactly how you would use the Strategy pattern to break this God Class apart.
  • Q: Explain how the Strategy pattern heavily relies on the SOLID "Dependency Inversion Principle."

14. FAQs

Q: How does the Context pass data to the Strategy? A: Two ways. 1) The Context passes exactly the variables the Strategy needs as arguments (execute($amount)). 2) The Context passes *itself* to the Strategy (execute($this)), allowing the Strategy to query the Context for whatever data it needs. The first is more decoupled; the second is more flexible.

15. Summary

In Chapter 14, we cured algorithmic bloat. We identified that massive, hardcoded switch statements are fragile, violation-heavy anti-patterns. By deploying the Strategy Pattern, we encapsulated volatile, changing algorithms into isolated, easily testable classes. We established a Context capable of seamlessly swapping its internal logic at runtime via simple interface injection. This architectural decoupling ensures that adding new features (like a new payment gateway or a new routing map) requires zero modification to our core application logic.

16. Next Chapter Recommendation

Our objects can swap algorithms at runtime. But what if we need to package an entire request or action into a standalone object so we can queue it or undo it later? Proceed to Chapter 15: Command Pattern.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·