0
0
PHPprogramming~15 mins

Strategy pattern in PHP - Deep Dive

Choose your learning style9 modes available
Overview - Strategy Pattern
What is it?
The Strategy Pattern is a way to change how a program does something by swapping different methods or algorithms at runtime. Instead of writing one fixed way, you create many small pieces that do the same job differently. Then, you pick which piece to use when the program runs. This helps make programs flexible and easier to change.
Why it matters
Without the Strategy Pattern, programs often have big blocks of code with many choices mixed together, making them hard to read and change. If you want to add a new way to do something, you might have to rewrite or break existing code. The Strategy Pattern solves this by separating each way into its own part, so you can add or change methods without touching the rest. This saves time and reduces bugs.
Where it fits
Before learning the Strategy Pattern, you should understand basic object-oriented programming concepts like classes, interfaces, and polymorphism. After mastering it, you can explore other design patterns like Factory, Decorator, or State, which also help organize code and behavior.
Mental Model
Core Idea
The Strategy Pattern lets you swap different ways to do a task inside a program without changing the program’s main structure.
Think of it like...
Imagine you have a toolbox with different screwdrivers: flathead, Phillips, and Torx. Depending on the screw, you pick the right screwdriver to get the job done. The Strategy Pattern is like choosing the right screwdriver for the screw without changing the toolbox itself.
┌───────────────┐
│   Context     │
│ (uses a task) │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│  Strategy     │◄─────────────┐
│ (interface)   │              │
└──────┬────────┘              │
       │                       │
       ▼                       │
┌─────────────────┐   ┌───────────────────┐
│ ConcreteStrategyA│ │ ConcreteStrategyB │
│ (one way to do) │ │ (another way)     │
└─────────────────┘ └───────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding the Problem of Fixed Behavior
🤔
Concept: Programs often have fixed ways to do tasks, making changes hard.
Imagine a program that calculates discounts. If the discount rules change often, hardcoding them means changing the program every time. This step shows why fixed behavior is a problem.
Result
You see that changing behavior requires rewriting code, which is slow and error-prone.
Understanding why fixed behavior causes problems helps you appreciate the need for flexible design.
2
FoundationBasics of Interfaces and Polymorphism
🤔
Concept: Interfaces let different classes share the same method names, so they can be swapped easily.
In PHP, an interface defines methods without code. Classes that implement it must write those methods. This allows the program to use any class that follows the interface without knowing details.
Result
You can write code that works with many classes through one interface.
Knowing interfaces and polymorphism is key to swapping behaviors without changing the main code.
3
IntermediateDefining the Strategy Interface
🤔
Concept: Create an interface that all strategies will follow to ensure they can be swapped.
Result
You have a contract that all discount methods must follow.
Defining a clear interface ensures all strategies can replace each other seamlessly.
4
IntermediateImplementing Concrete Strategies
🤔
Concept: Write different classes that implement the strategy interface with unique behavior.
percent = $percent; } public function calculate(float $price): float { return $price * (1 - $this->percent / 100); } } ?>
Result
You have multiple ways to calculate discounts, each in its own class.
Separating behaviors into classes makes it easy to add or change discount methods.
5
IntermediateUsing Context to Apply Strategies
🤔
Concept: Create a class that uses a strategy to perform the task, allowing strategy swapping at runtime.
totalPrice = $totalPrice; $this->discountStrategy = $strategy; } public function setDiscountStrategy(DiscountStrategy $strategy): void { $this->discountStrategy = $strategy; } public function getFinalPrice(): float { return $this->discountStrategy->calculate($this->totalPrice); } } ?>
Result
The cart can change how it calculates discounts anytime without changing its own code.
Using a context class to hold and use strategies enables flexible behavior changes.
6
AdvancedSwitching Strategies Dynamically
🤔Before reading on: Do you think you can change the discount method after creating the cart? Commit to yes or no.
Concept: You can change the strategy object inside the context at any time to alter behavior dynamically.
getFinalPrice(); // 100 $cart->setDiscountStrategy(new PercentageDiscount(20)); echo $cart->getFinalPrice(); // 80 ?>
Result
The output shows the price first without discount, then with 20% off after strategy change.
Knowing that strategies can be swapped anytime allows programs to adapt behavior on the fly.
7
ExpertAvoiding Common Pitfalls and Overuse
🤔Quick: Is the Strategy Pattern always the best choice for changing behavior? Commit to yes or no.
Concept: The Strategy Pattern adds complexity and is best used when multiple interchangeable behaviors exist and change often.
Using the pattern for simple or rarely changed behavior can make code harder to read. Sometimes simple conditionals or other patterns like State or Template Method are better.
Result
You learn when to apply the pattern wisely to avoid unnecessary complexity.
Understanding the tradeoffs prevents misuse and keeps code clean and maintainable.
Under the Hood
At runtime, the context holds a reference to a strategy object that implements a common interface. When the context needs to perform the task, it calls the method on the strategy object. Because the strategy can be swapped, the behavior changes without modifying the context. This works because PHP supports polymorphism, allowing objects of different classes to be treated uniformly if they share an interface.
Why designed this way?
The Strategy Pattern was designed to separate algorithms from the clients that use them, promoting open/closed principle: open for extension but closed for modification. It avoids large conditional statements by encapsulating each behavior in its own class. Alternatives like subclassing the context for each behavior were less flexible and led to class explosion.
┌───────────────┐
│   Context     │
│ ┌───────────┐ │
│ │Strategy   │◄┼─────────────┐
│ └───────────┘ │             │
└──────┬────────┘             │
       │                      │
       ▼                      ▼
┌─────────────────┐    ┌─────────────────┐
│ ConcreteStrategyA│    │ ConcreteStrategyB│
│ (algorithm 1)   │    │ (algorithm 2)    │
└─────────────────┘    └─────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does the Strategy Pattern mean you must always create a new class for every small behavior change? Commit yes or no.
Common Belief:You must create a separate class for every tiny variation of behavior.
Tap to reveal reality
Reality:You only create separate strategy classes for meaningful, reusable behaviors. Small tweaks can be handled by parameters or simpler methods.
Why it matters:Creating too many tiny classes leads to unnecessary complexity and harder maintenance.
Quick: Is the Strategy Pattern only useful for changing algorithms? Commit yes or no.
Common Belief:The Strategy Pattern is only for swapping algorithms, nothing else.
Tap to reveal reality
Reality:It can be used to swap any behavior or policy, like sorting methods, validation rules, or formatting styles.
Why it matters:Limiting the pattern to algorithms reduces its usefulness and creative application.
Quick: Does using the Strategy Pattern always improve code clarity? Commit yes or no.
Common Belief:Using the Strategy Pattern always makes code clearer and better.
Tap to reveal reality
Reality:If overused or applied to simple cases, it can make code more complex and harder to follow.
Why it matters:Misusing the pattern can confuse developers and increase bugs.
Quick: Can the Strategy Pattern replace all conditional statements? Commit yes or no.
Common Belief:The Strategy Pattern can and should replace all if-else or switch statements.
Tap to reveal reality
Reality:It is best for cases with multiple interchangeable behaviors, but simple conditionals are sometimes clearer and more efficient.
Why it matters:Trying to replace every conditional with strategies can overcomplicate simple logic.
Expert Zone
1
Some strategies can share common code by using abstract classes, reducing duplication while keeping flexibility.
2
Strategies can be combined or chained to create complex behaviors without changing the context.
3
Dependency injection frameworks can manage strategy objects, making swapping easier and decoupling creation from usage.
When NOT to use
Avoid the Strategy Pattern when behavior changes are rare or simple, or when the overhead of many classes outweighs benefits. Use simpler conditionals or the Template Method pattern when behavior varies only slightly and subclasses are manageable.
Production Patterns
In real systems, the Strategy Pattern is used for payment methods, sorting algorithms, logging policies, or feature toggles. It often works with dependency injection containers to swap strategies based on configuration or user input without code changes.
Connections
Dependency Injection
Builds-on
Understanding Dependency Injection helps manage and swap strategy objects cleanly, improving flexibility and testability.
Open/Closed Principle
Supports
The Strategy Pattern is a practical way to follow the Open/Closed Principle by allowing behavior extension without modifying existing code.
Evolutionary Biology
Analogy in adaptation
Just like species adapt by switching survival strategies to fit environments, programs use the Strategy Pattern to adapt behavior to changing needs.
Common Pitfalls
#1Creating too many tiny strategy classes for minor behavior differences.
Wrong approach:
Correct approach:percent = $percent; } public function calculate(float $price): float { return $price * (1 - $this->percent / 100); } } // One class with parameter for percent ?>
Root cause:Misunderstanding that strategy classes should represent meaningful behavior units, not every small variation.
#2Using the Strategy Pattern for behavior that never changes.
Wrong approach:
Correct approach:
Root cause:Applying the pattern without real need for interchangeable behaviors adds unnecessary complexity.
#3Trying to replace all conditional logic with strategies.
Wrong approach:
Correct approach:
Root cause:Misapplying the pattern to simple cases where conditionals are clearer and more efficient.
Key Takeaways
The Strategy Pattern separates different ways to do a task into interchangeable classes, making programs flexible.
It relies on interfaces and polymorphism to swap behaviors without changing the main program code.
Using a context class to hold and use strategies allows changing behavior at runtime easily.
Overusing the pattern can add complexity; it is best for cases with multiple meaningful, changeable behaviors.
Understanding when and how to apply the Strategy Pattern leads to cleaner, more maintainable, and adaptable code.