Subscribe to the Articles RSS Feed

PHP Design Patterns: The 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, pattern based programming is becoming an easier path to follow and the benefits are many.

Out of the many patterns I have studied the one that stood out for me as being the most immediately accessible and useful was 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 through the use of an example so we will imagine we are developing a system that manages the billing of project work. Using the procedural style of code that is often churned out using PHP it is quite likely that you would see the following section of code repeated several times throughout the system when the price of the project needs to be calculated.

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 area of the system. 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 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 impliments 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 make apparent some of the benefits to this pattern.

  • Minimising the replication of conditionals through code will reduce the chances of encountering bugs and make maintenance much easier.
  • 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. The result is minimal interference to the existing system which will lead to quicker changes.

Obviously this is a very brief introduction to the pattern. If you want to learn more then the following links will provide you with some more reading:

3 Comments

Hey! Great site! Love the fish…

said Emma on March 12, 2009 @ 9:23 pm

Really cool design work Marky Mark. Technical talk is impressive too. Just goes to show what high quality developers Bitopia employ!

said Steven Smith on March 13, 2009 @ 9:51 am

Maybe this would be a good idea in some of our larger projects. I’m not a fan of trying to hunt down bugs in 200 different php files.

said James on March 26, 2009 @ 9:52 pm

Leave a comment

Enter your Name
Enter your Email
Enter your URL