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

Some notes about transportation problem

Hello guys. After work I remembered my studying at university. My first thoughts is about solving Monge–Kantorovich transportation problem using a modification of simplex method known as Method of Potentials. Transportation theory investigates methods for optimal allocation resources among consumers and transportation them with minimum cost. For example, suppose we have some factories which provide materials and shops which consume it. (To be continued)

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

Docker multi-stage build in Action

Hi everyone, today I want to show how to create the small docker image for deploying the application. I've an application which consists of a backend(go application) and angular based front-end application. So let's create the Dockerfile and step by step fill it with commands. I started with frontend Next I added the golang builder For avoiding, the certificate signed by unknown authority error during HTTP request I add trusted certificates (details more here Stackoverflow issue ) Finally, copy all items to the end image I keep my container on the quay.io so everyone can see logs and pull the container docker pull quay.io/vdzundza/shoper All Dockerfile listing here Github Gist Thanks everyone !