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();

Leave a Reply




You may use the tags listed below in your comments:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>