Decorator design pattern is used to dynamically add new functionality to an existing class instance. In the example below, we will be selling a Mercedes make car but will add tiptronic transmission and leather seats to it.


Classes


MercedesSaleInterface


interface MercedesSaleInterface
{
public function calculatePrice(): float;

public function getDescription(): string;
}

MercedesSale


class MercedesSale implements MercedesSaleInterface
{
public function calculatePrice(): float
{
return 20000.96;
}

public function getDescription(): string
{
return 'Mercedes';
}
}

CarSaleDecorator


abstract class CarSaleDecorator implements MercedesSaleInterface
{
protected $mercedesSale;

public function __construct(MercedesSaleInterface $mercedesSale)
{
$this->mercedesSale = $mercedesSale;
}
}

Tiptronic


class Tiptronic extends CarSaleDecorator
{
public function calculatePrice(): float
{
return $this->mercedesSale->calculatePrice() + 1000.01;
}

public function getDescription(): string
{
return $this->mercedesSale->getDescription() . ' with tiptronic transmission';
}
}

LeatherSeat


class LeatherSeat extends CarSaleDecorator
{
public function calculatePrice(): float
{
return $this->mercedesSale->calculatePrice() + 100.02;
}

public function getDescription(): string
{
return $this->mercedesSale->getDescription() . ' with leather seats';
}
}

Usage


$mercedesSale = new MercedesSale();
echo $mercedesSale->calculatePrice().PHP_EOL;
echo $mercedesSale->getDescription().PHP_EOL;

$mercedesSale = new Tiptronic($mercedesSale);
echo $mercedesSale->calculatePrice().PHP_EOL;
echo $mercedesSale->getDescription().PHP_EOL;

$mercedesSale = new LeatherSeat($mercedesSale);
echo $mercedesSale->calculatePrice().PHP_EOL;
echo $mercedesSale->getDescription().PHP_EOL;

Result


20000.96
Mercedes

21000.97
Mercedes with tiptronic transmission

21100.99
Mercedes with tiptronic transmission with leather seats