Strategy Design Pattern – Usage and Example in PHP

Strategy design patterns is a behavioral design pattern that allow you select a algorithm from the available algorithms at the runtime. Client object can take any algorithm based on its need. It lets you choose strategy independently from client that use it. Each strategy encapsulated in itself, so client object can choose any strategy depending on requirement. Through this pattern we can define number of algorithms/strategies without touching the base class or the class which is core of the business. This will save testing whole lots of class and its depending class.

We could have defined various strategies in a single class as methods. In this case, we need to change the class implementation in case of new strategy come. Other problem is that a class inheriting the base class will automatically gets the base class behaviors. What if those subclasses inheriting behaviors does not need new strategy defined in base class! Those sub classes need to be identified and the undesired behavior/algorithms need to be overridden with empty implementation. So,  in case, where new strategies can be added to base class or the part of the code which can change need to sent to different encapsulated class. Here we are favoring  composition over inheritance. Now, new algorithm added will not get added to inherited class.

Below is an example PHP code showcasing Strategy Pattern. This example is a modified code from IBM article to give you better feel of strategy pattern. The modified code pass whole base class object to strategy. The code at that article does not need to do so but our code is an example short code and we need to showcase the strategy pattern.


<?php
interface IStrategy
{
  function filter(UserList $user );
}
class FindAfterStrategy implements IStrategy
{
  private $_name;
  public function __construct( $name )
  {
    $this->_name = $name;
  }
  public function filter(UserList $users )
  {
	  foreach ($users->list as $user) {
		  if (strcmp( $this->_name, $user ) <= 0) {
				$filtered[] = $user;
		  }
	  }
	  return $filtered;
  }
}
class RandomStrategy implements IStrategy
{
  public function filter(UserList $users )
  {
	  foreach ($users->list as $user) {
		if (rand( 0, 1 ) >= 0.5)
			$filtered[] = $user;
	  }
	return $filtered;
  }
}
class UserList
{
  public $list = array();
  public function __construct( $names )
  {
    if ( $names != null )
    {
      foreach( $names as $name )
      {
        $this->list []= $name;
      }
    }
  }
  public function add( $name )
  {
    $this->list[] = $name;
  }
  public function find( $filter )
  {
    $recs = array();
    $recs = $filter->filter( $this );
    return $recs;
  }
}
$ul = new UserList( array( "Andy", "Jack", "Lori", "Megan" ) );
$f1 = $ul->find( new FindAfterStrategy( "J" ) );
print_r( $f1 );
$f2 = $ul->find( new RandomStrategy() );
print_r( $f2 );
?>

The program gives you two sample strategies which select users based on algorithm. Random Strategy is random and it sometimes can give you empty user list.

Here is another example from Aaron Saray's Professional PHP Design Patterns book on design pattern:


<?php
class CDAsXMLStrategy {
	public function get(CDusesStrategy $cd) {
		$doc = new DomDocument();
		$root = $doc->createElement('CD');
		$root = $doc->appendChild($root);
		$title = $doc->createElement('TITLE', $cd->title);
		$title = $root->appendChild($title);
		$band = $doc->createElement('BAND', $cd->band);
		$band = $root->appendChild($band);
		return $doc->saveXML();
	}
}
class CDAsJSONStrategy  {
	public function get(CDusesStrategy $cd) {
		$json = array();
		$json['CD']['title'] = $cd->title;
		$json['CD']['band']  = $cd->band;
		return json_encode($json);
	}
}
class CDusesStrategy {
	public $title = '';
	public $band = '';
	protected $_strategy;
	public function __construct($title, $band) {
		$this->title = $title;
		$this->band  = $band;
	}
	public function setStrategyContext ($strategyObject)
	{
		$this->_strategy = $strategyObject;
	}
	public function get()
	{
		return $this->_strategy->get($this);
	}
}
$externalBand = 'Never Again';
$externalTitle = 'Waste of a Rib';
$cd = new CDusesStrategy($externalTitle, $externalBand);
$cd->setStrategyContext(new CDAsXMLStrategy());
print '<textarea cols=50 rows=10>' . $cd->get($cd) . '</textarea>';
echo '<hr>';
$cd->setStrategyContext(new CDAsJSONStrategy());
print $cd->get($cd);
?>

The book code can be downloaded from here.

Comments are open for an year period. Please, write here on Facebook page.