Today I want to explain how to use strategy design pattern in PHP. I tried to use this pattern when I want decouple algorithms for calculating something at runtime. For example, we can dynamically changing methods which will be calculate price of some items using some logic.
Create car, for example:
Suppose we want to separate method which will calculate price with different strategies. Create interface
which will be implemented in each strategy.
Now we can create simple discount strategy for calculating.
And implement second strategy - if invoice has more than some quantity of cars we subtract percents from total bill.
And finally using strategy pattern:
Output:
Create car, for example:
namespace strategy; abstract class Item{ abstract function getPrice(); } class Car extends Item{ protected $price; public $name; protected $isTuned; public function __construct($name, $price, $isTuned){ $this->name = $name; $this->price = $price; $this->isTuned = $isTuned; } /** * @return bool */ public function isTuned(){ return $this->isTuned; } public function getPrice(){ return $this->price; } }
Suppose we want to separate method which will calculate price with different strategies. Create interface
which will be implemented in each strategy.
namespace strategy; interface IPriceStrategy { /** * @param Item[] $items * @return mixed */ public function calculatePrice(array $items); }
Now we can create simple discount strategy for calculating.
class DiscountStrategy implements IPriceStrategy { private $discount = 0; /** * @param $discount - in percent * @throws \Exception */ public function __construct($discount) { if ($discount < 0) throw new \Exception('Discount must be greater or equal 0'); $this->discount = $discount; } /** * @param Item[] $items * @return mixed */ public function calculatePrice(array $items) { $price = 0; foreach ($items as $item) { $price = $price + $item->getPrice(); } return $price * ($this->discount / 100); } }
And implement second strategy - if invoice has more than some quantity of cars we subtract percents from total bill.
class DiscountManyCars implements IPriceStrategy { private $discount; private $discountQuantities; public function __construct($discount, $discountQuantities) { $this->discount = $discount; $this->discountQuantities = krsort($discountQuantities); } /** * @param Item[] $items * @return mixed */ public function calculatePrice(array $items) { $count = count($items); $price = 0; foreach ($items as $item) { $price = $price + $item->getPrice(); } if ($count >= $this->discountQuantities) { $price = $price * ($this->discount / 100); } return $price; } }
And finally using strategy pattern:
namespace strategy; require_once 'Car.php'; require_once 'Invoice.php'; require_once 'IPriceStrategy.php'; $invoice = new Invoice(); $car1 = new Car('BMV', 1200000, false); $car2 = new Car('MERCEDES', 100000, true); $car3 = new Car('AUDI', 300000, false); $invoice->addCar($car1); $invoice->addCar($car2); $invoice->addCar($car2); $invoice->addCar($car2); $invoice->addCar($car2); $invoice->addCar($car3); $invoice->addCar($car3); $invoice->addCar($car3); $discountStrategy = new DiscountStrategy(20); $manyDiscountStrategy = new DiscountManyCars(30, 6); $priceOne = $invoice->calculatePrice($discountStrategy); $priceTwo = $invoice->calculatePrice($manyDiscountStrategy); setlocale(LC_MONETARY, 'en_US'); $fmt = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); echo "first strategy: ", $fmt->formatCurrency($priceOne, "EUR"), ""; echo "second strategy: ", $fmt->formatCurrency($priceTwo, "EUR"), "";
Output:
first strategy: €500,000.00 second strategy: €750,000.00
Comments