PHP Design Patterns: Strategy Pattern

I have recently finished reading Matt Zandstra’s PHP5 Objects, Patterns and Practice. With PHP5′s much improved support for object oriented coding, tried and tested design patterns have become much more applicable to PHP development.

I will be looking at a number of design patterns of the coming months but for this post we will focus on the strategy pattern. The strategy pattern employs the principles of polymorphism to help prevent recurring conditionals throughout your code.

I find these patterns are best demonstrated with examples so we will imagine we are developing a system that manages the billing of project work. One of the most common tasks a system like this will be required to carry out is calculate the total price of a project.

If we look at a poorly thought out implementation of this pricing logic we would probably see the following section of code repeated several times throughout the system.

switch ($project->charge_type) {
    case 'fixed_price':
        $price = $project->fixed_price;
    break;
    case 'hourly_rate':
        $price = $total_hours * $hourly_rate;
    break;
}

Conditionals that are replicated many times throughout a system are a typical example of what is known as a code smell. Such code smells are a good indication that you need to re-factor your code. This is where the Strategy pattern comes into play.

The strategy pattern attempts to circumvent one of the most common problems with object oriented systems; the object that knew too much. By separating and encapsulating individual responsibilities within other classes we can keep our objects focused on managing their own section of logic.

A project object, for example, should be concentrating on managing data specific to a project. If we give it responsibility for managing the pricing structures as well then we are starting to increase both the likeliness of bugs and the difficulty of maintenance. The strategy pattern can be used here to separate the pricing logic from the core project object like so:

interface PricingStrategy {
    function price() {}
}

abstract class PriceStrategy implements PricingStrategy {
    function __construct() {}
    function price() {}
}

class FixedPriceStrategy extends PriceStrategy {
    function price() {
        return $fixed_rate_price;
    }
}

class HourlyPriceStrategy extends PriceStrategy {
    function price() {
        return $hours * $hourly_rate;
    }
}

class Project {
   public $pricing_structure;

    function __construct(PriceStrategy $pricing_strategy) {
        $this->pricing_structure = $pricing_strategy;
    }
}

By implementing the PricingStrategy interface each of the pricing objects guarantees support for the price function. As a result the main project object can hold a reference to any of these and call the price function knowing that it will be supported. Now instead of having messy conditionals littered throughout the code a project object can be instantiated by passing any of the chosen pricing structure objects to it’s constructor as follows:

$project = new Project(new FixedPriceStrategy());

echo 'The cost of this project is: '.$project->pricing_structure->Price();

This is of course a very crude and stripped down example but none the less it should demonstrate some of the benefits to this pattern.

  • Minimising the replication of conditionals through code will reduce the chances of encountering bugs and make maintenance simpler.
  • The design results in simplified client coding meaning other members of the team can easily implement your code in other parts of the system without having to know the inner working of the pricing logic.
  • Addition of new pricing strategies becomes a simple matter of adding a new class. Meaning new pricing structures can be integrated more quickly and reliably.

If you want to learn more then the following links will provide you with some more reading:

2 Responses to PHP Design Patterns: Strategy Pattern

  1. Chris Temple says:

    This is a very good and clear explanation of this design pattern. Just thought I would comment on how well you demonstrated its benefits with such minimal code. You usually don’t notice how beneficial the Strategy design pattern is until your code begins expanding. It makes life so much easier in the long run!

    Great explanation, was a nice read :)

  2. Interface says:

    Thank you very for the post. I also think strategy is seminar to polymorphism idea of OOP.

    Interface method don’t have the body :)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>