Skip to main content

PHP Design Patterns - Strategy

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:
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

Popular posts from this blog

New Personal Website

Hello World, hello my blog again. I have good news, finally, I created my website , I do not know exactly what is the main goal for that and how it will be updated. Now I want to sync my current posts from the blogger platform and personal website, it can be easily done by using the `Blogger API` with some extra requirements which I want to have.   Especially,   - able to show/hide the post separately from blogger (1)   - use custom posts order (2)   - add some extra information besides tags (3)    For instance, technology stack, team size, etc. - add a possibility to use any 3rd party code highlighter instead of post-computed HTML from blogger (4) I think that the 4 the most required and nice feature - able to sync manually, or use cron for syncing with blogger (5)   There is some initial schema of my application   This is a pretty simple solution: two go services, one for fetching data, checking referential integr...

Університет нафти і газу

Всім привіт. Я поступив в національний технічний університет Нафти і Газу. Поступив на 2 курс, хоча мав б бути на третьому. Я дякую, за те, що поступив на другий курс на держ. форму. Але не все так просто. Потрібно перезаразувати години предметів, які вчили в універі на 1 і частково на 2 курсі, для того щоб без проблем перейти на 3 курс. На рахунок програмування, майже нічого нового немає. Хіба що будем вчити Java на на предметі "технологія розробки ПЗ". Ось і все, що я хотів написати. Всім удачі!