Hack71.Separate What from How with Strategies


Hack 71. Separate What from How with Strategies

Use the Strategy pattern to abstract the code that traverses structures from the code that operates on those structures.

You use the Strategy pattern to abstract the processing of an object, allowing how an object is processed to be separated from where the object is located.

In this hack, I'll use a car chooser as an example. This code will recommend a car based on some search criteria. In this case, I will provide my specs for an ideal car and let the code pick the car that most closely matches my dream specs. The value of the Strategy pattern is that I can alter the car comparison code independently of the car selection code.

The UML for this hack is shown in Figure 7-5. The CarChooser object uses a CarWeighter object to compare each Car to the ideal model. Then the best Car match is returned to the client.

7.6.1. The Code

Save the code in Example 7-5 as strategy.php.

Figure 7-5. The relationship between the CarChooser, CarWeighter, and Car objects


Example 7-5. An example of the Strategy pattern
 <?php class Car {   public $name;   public $speed;   public $looks;   public $mileage;   public function Car( $name, $speed, $looks, $mileage )   {     $this->name = $name; $this->speed = $speed; $this->looks = $looks; $this->mileage = $mileage;   } } class CarWeighter {   private function diff( $a, $b )   {     return abs( $a - $b );   }      public function weight( $a, $b )   {     $d = 0; $d += $this->diff( $a->speed, $b->speed ); $d += $this->diff( $a->looks, $b->looks ); $d += $this->diff( $a->mileage, $b->mileage ); return ( 0 - $d );   } } class CarChooser {   private $ideal;   private $alg;   function CarChooser( $ideal, $alg )   {     $this->ideal = $ideal; $this->alg = $alg;      }      public function choose( $carlist )   {     $minrank = null; $found = null; $alg = $this->alg; foreach( $carlist as $car ) {   $rank = $alg->weight( $this->ideal, $car );   if ( !isset( $minrank ) ) $minrank = $rank;   if ( $rank >= $minrank )   {     $minrank = $rank; $found = $car;   } } return $found;   } } function pickCar( $car ) {      $carlist = array();   $carlist []= new Car( "zippy", 90, 30, 10 );   $carlist []= new Car( "mom'n'pop", 45, 30, 55 );   $carlist []= new Car( "beauty", 40, 90, 10 );   $carlist []= new Car( "enviro", 40, 40, 90 );   $cw = new CarWeighter();   $cc = new CarChooser( $car, $cw );   $found = $cc->choose( $carlist );   echo( $found->name."\n" ); } pickCar( new Car( "ideal", 80, 40, 10 ) ); pickCar( new Car( "ideal", 40, 90, 10 ) ); ?> 

Starting at the top of the file, I define the Car class, which holds the car name and the metrics for speed, looks, and mileage. Each is rated from 0 to 100 (largely to make the math easy). Then comes the CarWeighter, which compares two cars and returns a comparison metric. Finally, there's the CarChooser, which uses a CarWeighter to select the best car based on some input criteria. The pickCar( ) function creates a set of cars and then uses a CarChooser to choose the car from the list that best fits the criteria (passed in via another Car object).

The test code at the bottom of the file then asks for two carsone that is heavily weighted in the speed category, and another that is strongly weighted on looks.

7.6.2. Running the Hack

You run this hack on the command line with the PHP interpreter:

 % php strategy.php zippy beauty 

The output shows that the car recommended to me if I want speed is the "zippy" car: a good approximation. The car recommended to me if I want something a little sexier is the "beauty" car. Excellent!

The code that deduces whether a car is a good match is totally abstracted away from the code that traverses the car list and picks one from that list. You can change the algorithm that weights a certain car independently of the code that picks which is the right car from the weighted list. For example, you can add the cars that have interested you recently or that you have owned in the past into the weighting algorithm. Or you can change the picker code to select the top three and provide a choice among them.



PHP Hacks
PHP Hacks: Tips & Tools For Creating Dynamic Websites
ISBN: 0596101392
EAN: 2147483647
Year: 2006
Pages: 163

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net