Design Pattern: Decorator in PHP

Now, on the next series from the Head First Design Patterns book – the decorator pattern. The decorator pattern is used to attach additional responsibilities to an object dynamically. This provides a more flexible alternative to subclassing in order to add on more functionality.
When does this get used? Say for example you’re writing an point of sale system for a pizza store. Customers can choose from a variety of toppings to be added on to the pizza. You could have a super class that identifies all the toppings, but as new toppings get added or old toppings get removed, that super class is going to be going through a lot of changes. The decorator pattern comes to the rescue here by allowing us to add just a new class for the new topping.
If you want to tinker with the files, here’s a copy.
abstract class Beverage{
protected $description = "Unknown Beverage";
public function getDescription(){
return $this->description;
}
public abstract function cost();
}
include_once("beverage.php");
abstract class CondimentDecorator extends Beverage{
public function getDescription(){
throw new Exception("getDescription must be overridden");
}
}
include_once("beverage.php");
class DarkRoast extends Beverage{
public function __construct(){
$this->description = "Dark Roast";
}
public function cost(){
return 0.99;
}
}
include_once("beverage.php");
class Decaf extends Beverage{
public function __construct(){
$this->description = "Decaf";
}
public function cost(){
return 1.05;
}
}
include_once("beverage.php");
class Espresso extends Beverage{
public function __construct(){
$this->description = "Espresso";
}
public function cost(){
return 1.99;
}
}
include_once("beverage.php");
class HouseBlend extends Beverage{
public function __construct(){
$this->description = "House Blend Coffee";
}
public function cost(){
return 0.89;
}
}
include_once("beverage.php");
abstract class CondimentDecorator extends Beverage{
public function getDescription(){
throw new Exception("getDescription must be overridden");
}
}
include_once("beverage.php");
include_once("condimentDecorator.php");
class Milk extends CondimentDecorator{
private $beverage;
public function __construct(Beverage $beverage){
$this->beverage = $beverage;
}
public function getDescription(){
return $this->beverage->getDescription() . ", Steamed Milk";
}
public function cost(){
return 0.10 + $this->beverage->cost();
}
}
include_once("beverage.php");
include_once("condimentDecorator.php");
class Mocha extends CondimentDecorator{
private $beverage;
public function __construct(Beverage $beverage){
$this->beverage = $beverage;
}
public function getDescription(){
return $this->beverage->getDescription() . ", Mocha";
}
public function cost(){
$cost = $this->beverage->cost();
return 0.20 + $this->beverage->cost();
}
}
include_once("beverage.php");
include_once("condimentDecorator.php");
class Soy extends CondimentDecorator{
private $beverage;
public function __construct(Beverage $beverage){
$this->beverage = $beverage;
}
public function getDescription(){
return $this->beverage->getDescription() . ", Soy";
}
public function cost(){
return 0.15 + $this->beverage->cost();
}
}
include_once("beverage.php");
include_once("condimentDecorator.php");
class Whip extends CondimentDecorator{
private $beverage;
public function __construct(Beverage $beverage){
$this->beverage = $beverage;
}
public function getDescription(){
return $this->beverage->getDescription() . ", Whip";
}
public function cost(){
return 0.10 + $this->beverage->cost();
}
}
include_once("espresso.php");
include_once("decaf.php");
include_once("houseBlend.php");
include_once("darkRoast.php");
include_once("mocha.php");
include_once("soy.php");
include_once("milk.php");
include_once("whip.php");
class StarbuzzCoffee{
public static function main(){
$beverage = new Espresso();
echo($beverage->getDescription() . " $" . $beverage->cost());
$beverage2 = new DarkRoast();
$beverage2 = new Mocha($beverage2);
$beverage2 = new Mocha($beverage2);
$beverage2 = new Whip($beverage2);
echo("<br />" . $beverage2->getDescription() . " $" . $beverage2->cost());
$beverage3 = new DarkRoast();
$beverage3 = new Soy($beverage3);
$beverage3 = new Mocha($beverage3);
$beverage3 = new Whip($beverage3);
echo("<br />" . $beverage3->getDescription() . " $" . $beverage3->cost());
}
}
StarbuzzCoffee::main();
