Design Patterns Strategy Pattern

The main intent of the Strategy Design Pattern is to design a family of Algorithms which can then be used interchangeably by encapsulating each one. Simply put, we have a list of algorithm or ways to do a specific task and we create an interface from which we can access these algorithms without knowing how they are implemented. By this way we work with the interface and not the implementation.


Structure

Strategy Design Pattern Structure
Strategy Design Pattern Structure

We will use this pattern to create box shadow based on the user’s browser.

StrategyInterface

This declares an interface that is common to all the algorithms. The client uses this interface to access the algorithms.

/**
 * StrategyInterface
 */
interface ElementFeatures {
    public function addBoxShadow(); // Algorithm Interface
}

ConcreteImplementation

Implements the algorithms by using the Strategy Interface.

/**
 * ConcreteImplementations for various algorithms.
 *
 * These Concrete classes implements the interface defined
 * by the StrategyInterface
 */
class Firefox implements ElementFeatures {
    public function addBoxShadow() {
        return '-moz-box-shadow: 3px 3px 4px #444;';
    }
}

class Chrome implements ElementFeatures {
    public function addBoxShadow() {
        return '-webkit-box-shadow: 3px 3px 4px #444;';
    }
}

class InternetExplorer implements ElementFeatures {
    public function addBoxShadow() {
        return '-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(' . 
            'Strength=4, Direction=135, Color=\'#444444\')"filter: ' . 
            'progid:DXImageTransform.Microsoft.Shadow(Strength=4, ' . 
            'Direction=135, Color=\'#444444\');';
    }   
}

Client

The client is configured with a ConcreteImplementaion Object(new Firefox()) and it maintains a reference($browserElement in this case) to the StrategyInterface object.

/**
 * Client
 */
class BoxElement {
    public $browserElement = null; // StrategyInterface reference Object

    /**
     * ConcreteImplementation object is passed here.
     */
    public function __construct(ElementFeatures $browserType) {
        $this->browserElement = $browserType;
    }

    public function addEffect($effect) {
        $effect = 'add' . $effect;
        return $this->browserElement->$effect();
    }
}

Example

<?php
/**
 * StrategyInterface
 */
interface ElementFeatures {
    public function addBoxShadow(); // Algorithm Interface
}

/**
 * ConcreteImplementations for various algorithms.
 *
 * These Concrete classes implements the interface defined
 * by the StrategyInterface
 */
class Firefox implements ElementFeatures {
    public function addBoxShadow() {
        return '-moz-box-shadow: 3px 3px 4px #444;';
    }
}

class Chrome implements ElementFeatures {
    public function addBoxShadow() {
        return '-webkit-box-shadow: 3px 3px 4px #444;';
    }
}

class InternetExplorer implements ElementFeatures {
    public function addBoxShadow() {
        return '-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(' . 
            'Strength=4, Direction=135, Color=\'#444444\')"filter: ' . 
            'progid:DXImageTransform.Microsoft.Shadow(Strength=4, ' . 
            'Direction=135, Color=\'#444444\');';
    }   
}

/**
 * Client
 */
class BoxElement {
    public $browserElement = null; // StrategyInterface reference Object

    /**
     * ConcreteImplementation object is passed here.
     */
    public function __construct(ElementFeatures $browserType) {
        $this->browserElement = $browserType;
    }

    public function addEffect($effect) {
        $effect = 'add' . $effect;
        return $this->browserElement->$effect();
    }
}

/** 
 * Code which helps us find the browser used by user 
 *
 * $browser = method_that_finds_user_browser();
 *
 * switch($browser) {
 *   case 'Firefox':
 *     $browserObj = new Firefox();
 *   break;
 *   case 'InternetExplorer':
 *     $browserObj = new InternetExplorer();
 *   break;
 *   case 'Chrome':
 *     $browserObj = new Chrome();
 *   break;
 * }
 *
 */

// Assume the user is using firefox.
$browserObj = new Firefox();

$boxElement = new BoxElement($browserObj);
echo $boxElement->addEffect('boxShadow');
?>

In the above example we use this pattern to create the box shadow effect based on the user’s browser.