Skip to content

Instantly share code, notes, and snippets.

@thelowlypeon
Last active August 29, 2015 13:57
Show Gist options
  • Save thelowlypeon/9585326 to your computer and use it in GitHub Desktop.
Save thelowlypeon/9585326 to your computer and use it in GitHub Desktop.
<?php
/**
* Our base Coffee class, which has a cost, array of ingredients,
* and getters/setters. Note that this class is not extended or
* implemented, and decorators don't modify Coffee objects.
*/
class Coffee {
private $cost;
private $ingredients = array();
public function __construct($cost, $ingredients=array('coffee')) {
$this->cost = $cost;
if (!is_array($ingredients)) {
$ingredients = array($ingredients);
}
$this->ingredients = $ingredients;
}
public function getCost() { return $this->cost; }
public function getIngredients() { return $this->ingredients; }
}
/**
* Our base decorator class. In this example, the CoffeeDecorator is
* not an abstract class, though an alternate approach is to make the decorator
* abstract and then make each decorator extend it.
*/
class CoffeeDecorator {
protected $coffee;
protected $cost;
protected $ingredients = array();
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
$this->setCost();
$this->setIngredients();
}
public function setCost() {
$this->cost = $this->coffee->getCost();
}
public function setIngredients() {
$this->ingredients = $this->coffee->getIngredients();
}
public function getCost() { return $this->cost; }
public function getIngredients() { return $this->ingredients; }
public function getSortedIngredients() {
$ingredients = $this->getIngredients();
$arr = array();
foreach ($ingredients as $ingredient) {
$arr[$ingredient] = (array_key_exists($ingredient, $arr) ? $arr[$ingredient] : 0) + 1;
}
return $arr;
}
}
/**
* Here's our first decorator. Creating a MilkyCoffee will add
* milk to the ingredients, as well as a corresponding cost.
*
* Note again that this will not modify the original Coffee class.
*/
class MilkyCoffee extends CoffeeDecorator {
private $decorator;
protected $cost = 1;
protected $ingredients = array('Milk');
public function __construct(CoffeeDecorator $decorator) {
$this->decorator = $decorator;
$this->addMilk();
}
public function addMilk() {
$this->decorator->cost = $this->decorator->getCost() + $this->cost;
$this->decorator->ingredients = array_merge($this->ingredients, $this->decorator->getIngredients());
}
}
/**
* Like this MilkyCoffee decorator, this will add a cost and ingredients.
*/
class FoamyCoffee extends CoffeeDecorator {
private $decorator;
protected $cost = .5;
protected $ingredients = array('Steam', 'Milk');
public function __construct(CoffeeDecorator $decorator) {
$this->decorator = $decorator;
$this->addFoam();
}
public function addFoam() {
$this->decorator->cost = $this->decorator->getCost() + $this->cost;
$this->decorator->ingredients = array_merge($this->ingredients, $this->decorator->getIngredients());
}
}
/**
* Let's make some coffee
*/
function run() {
$coffee = new Coffee(1);
$decorator = new CoffeeDecorator($coffee);
echo "\n-------------\ninitial coffee: ($" . $coffee->getCost() . "):\n " . json_encode($coffee->getIngredients()) . "\n";
$milky = new MilkyCoffee($decorator);
echo "\nmilky coffee ($" . $decorator->getCost() . "):\n " . json_encode($decorator->getSortedIngredients()) . "\n";
$foamy = new FoamyCoffee($decorator);
echo "\nfoamy, milky coffee ($" . $decorator->getCost() . "):\n " . json_encode($decorator->getSortedIngredients()) . "\n";
echo "\n(adding foam...)";
$foamy->addFoam();
echo "\nsuper foamy, milky coffee: ($" . $decorator->getCost() . "):\n " . json_encode($decorator->getSortedIngredients()) . "\n";
echo "\nbase coffee: ($" . $coffee->getCost() . "):\n " . json_encode($coffee->getIngredients());
echo "\n-------------\n";
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment