The Strategy
pattern is used to separate an object from its algorithms. The core idea of the
pattern is the OOP principal of polymorphism.
More explicitly, a Strategy pattern is a group of algorithms
encapsulated inside classes that are made interchangeable so the algorithm can
vary depending on the class used. Strategies are useful when you would like to
decide at run time when to implement each algorithm. They can be used to vary
each algorithm’s usage by its context.
The Strategy pattern has three main components: the Strategy,
the Concrete Strategy, and the Context. The strategy is a common
interface that ties together all supported algorithms. Usually this class is
abstract. The concrete strategy is the implementation class where the logic for
each different algorithm lives in the group. The context is the object that
ties a concrete strategy to a particular code flow.
Advantage of the strategy pattern
As mentioned earlier, the motive behind the strategy pattern
is to separate an object from its algorithms. Removing the algorithms from the
host class and putting them in a separate class, enables the host to
concentrate on its own job. Otherwise, the host will get messy with all the
algorithms in itself with lot of if-else or switch-case statements.
Here’s an example.
Suppose a car renting service charges its customers
differently at different situations – sometimes based on kilometers travelled, sometimes
on hours of travel, and sometimes on a combination of both, depending on
festive seasons, off-seasons etc.
There’s a billing class in the application which prepares the bill for
the customer. Now the payable amount part needs a lot of calculations based on
the type of charge, distance and hours of travel resulting in a lot of if-else
or case statements. Addition of more billing algorithms results in inclusion of
more if-else statements. To make the situation better, we simply encapsulate
each faring algorithm in a separate class and depending on the context at runtime,
we decide which algorithm to choose. Addition of another faring algorithm is
done by simply adding another class i.e. extending the abstract class FareStrategy.
<?php
abstract class FareStrategy
{
abstract function calculateFare($kms, $hrs);
}
class HourlyFareStrategy extends FareStrategy
{
private $normalHours=8;
private $normalHourRate=250;
private $additionalHourRate=200;
function calculateFare($kms, $hrs)
{
if($hrs > $this->normalHours)
{
$fare=($this->normalHours*$this->normalHourRate)+(($hrs-$this->normalHours)*$this->additionalHourRate);
return $fare;
}
else
{
$fare=$hrs*$this->normalHourRate;
return $fare;
}
}
} //end class HourlyFareStrategy
class KmsFareStrategy extends FareStrategy
{
private $normalKms=100;
private $normalKmRate=15;
private $additionalKmRate=13;
function calculateFare($kms, $hrs)
{
if($kms>$this->normalKms)
{
$fare=($this->normalKms*$this->normalKmRate)+(($kms-$this->normalKms)*$this->additionalKmRate);
return $fare;
}
else
{
$fare=$kms*$this->normalKmRate;
return $fare;
}
}
}//end class KmsFareStrategy
class FaringContext
{
private $_fareStrategy;
public function __construct(FareStrategy $fareStrategy)
{
$this->_fareStrategy=$fareStrategy;
}
public function getFare($kms,$hrs)
{
return $this->_fareStrategy->calculateFare($kms,$hrs);
}
} //end class FaringContext
//main program
$context=new FaringContext(new HourlyFareStrategy());
$fare=$context->getFare(120,6);
echo $fare;
echo '<br />';
$context=new FaringContext(new KmsFareStrategy());
$fare=$context->getFare(120,6);
echo $fare;
?>
abstract class FareStrategy
{
abstract function calculateFare($kms, $hrs);
}
class HourlyFareStrategy extends FareStrategy
{
private $normalHours=8;
private $normalHourRate=250;
private $additionalHourRate=200;
function calculateFare($kms, $hrs)
{
if($hrs > $this->normalHours)
{
$fare=($this->normalHours*$this->normalHourRate)+(($hrs-$this->normalHours)*$this->additionalHourRate);
return $fare;
}
else
{
$fare=$hrs*$this->normalHourRate;
return $fare;
}
}
} //end class HourlyFareStrategy
class KmsFareStrategy extends FareStrategy
{
private $normalKms=100;
private $normalKmRate=15;
private $additionalKmRate=13;
function calculateFare($kms, $hrs)
{
if($kms>$this->normalKms)
{
$fare=($this->normalKms*$this->normalKmRate)+(($kms-$this->normalKms)*$this->additionalKmRate);
return $fare;
}
else
{
$fare=$kms*$this->normalKmRate;
return $fare;
}
}
}//end class KmsFareStrategy
class FaringContext
{
private $_fareStrategy;
public function __construct(FareStrategy $fareStrategy)
{
$this->_fareStrategy=$fareStrategy;
}
public function getFare($kms,$hrs)
{
return $this->_fareStrategy->calculateFare($kms,$hrs);
}
} //end class FaringContext
//main program
$context=new FaringContext(new HourlyFareStrategy());
$fare=$context->getFare(120,6);
echo $fare;
echo '<br />';
$context=new FaringContext(new KmsFareStrategy());
$fare=$context->getFare(120,6);
echo $fare;
?>