Skip to content

Instantly share code, notes, and snippets.

@mpratt
Last active October 12, 2016 13:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mpratt/5572524 to your computer and use it in GitHub Desktop.
Save mpratt/5572524 to your computer and use it in GitHub Desktop.
<?php
class Damage
{
protected $name;
protected $damagePoints = 10;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getDamage()
{
return $this->damagePoints;
}
}
$damage = new Damage('Rocky');
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
?>
<?php
/**
* Coger una piedra de fuego aumenta +2 el daño
*/
class StoneOfFire
{
protected $damage;
public function __construct($damage)
{
$this->damage = $damage;
}
public function getDamage()
{
return $this->damage->getDamage() + 2;
}
/**
* Este es un metodo mágico que permite usar metodos
* publicos que estén dentro del objeto que estamos decorando
* como por ejemplo el metodo "getName()"
*/
public function __call($method, $args)
{
return call_user_func_array(array($this->damage, $method), $args);
}
}
/**
* Coger una piedra de viento aumenta +7 el daño
*/
class StoneOfWind
{
protected $damage;
public function __construct($damage)
{
$this->damage = $damage;
}
public function getDamage()
{
return $this->damage->getDamage() + 7;
}
public function __call($method, $args)
{
return call_user_func_array(array($this->damage, $method), $args);
}
}
/**
* Digamos que el personaje tiene la piedra de fuego
*/
$damage = new StoneOfFire(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
/**
* Digamos que el personaje tiene la piedra de Viento
*/
$damage = new StoneOfWind(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
/**
* Digamos que el personaje tiene la piedra de Viento y la piedra de fuego
*/
$damage = new StoneOfFire(new StoneOfWind(new Damage('Rocky')));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
?>
<?php
/**
* Creo una clase abstracta con las funcionalidades
* comunes que tendrán los decoradores, para evitar
* la duplicación de codigo
*/
abstract class StoneDecorator
{
protected $damage;
protected $damagePoints;
public function __construct($damage)
{
$this->damage = $damage;
}
public function getDamage()
{
return $this->damage->getDamage() + $this->damagePoints;
}
public function __call($method, $args)
{
return call_user_func_array(array($this->damage, $method), $args);
}
}
// Coger una piedra de fuego aumenta +2 el daño
class StoneOfFire extends StoneDecorator { protected $damagePoints = 2; }
// Coger una piedra de viento aumenta +7 el daño
class StoneOfWind extends StoneDecorator { protected $damagePoints = 7; }
// Ahora si los ejemplos
$damage = new StoneOfFire(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
$damage = new StoneOfWind(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
$damage = new StoneOfFire(new StoneOfWind(new Damage('Rocky')));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
?>
<?php
/**
* Ejemplo 2:
* Clase con el precio de la arepa
*/
class Arepa
{
protected $basePrice = 1000;
public function getPrice()
{
return $this->basePrice;
}
}
/**
* Creo una clase abstracta con las funcionalidades
* comunes que tendrán los decoradores, para evitar
* la duplicación de codigo
*/
abstract class ArepaDecorator
{
protected $price;
protected $arepa;
public function __construct($arepa)
{
$this->arepa = $arepa;
}
public function getPrice()
{
return $this->arepa->getPrice() + $this->price;
}
}
/**
* Ahora si creo cada uno de los ingredientes y les asigno
* un precio
*/
class withCheese extends ArepaDecorator { protected $price = 500; }
class withMeat extends ArepaDecorator { protected $price = 1200; }
class withFish extends ArepaDecorator { protected $price = 2000; }
/**
* Ahora hagamos las pruebas
*/
$arepa = new Arepa();
echo 'Una arepa sola cuesta ' . $arepa->getPrice() . ' pesos' . PHP_EOL;
$arepa = new withCheese(new Arepa());
echo 'Una arepa con queso cuesta ' . $arepa->getPrice() . ' pesos' . PHP_EOL;
$arepa = new withMeat(new Arepa());
echo 'Una arepa con carne cuesta ' . $arepa->getPrice() . ' pesos' . PHP_EOL;
$arepa = new withFish(new Arepa());
echo 'Una arepa con pescado cuesta ' . $arepa->getPrice() . ' pesos' . PHP_EOL;
$arepa = new withFish(new withCheese(new withMeat(new Arepa())));
echo 'Una arepa con pescado, carne y queso cuesta ' . $arepa->getPrice() . ' pesos' . PHP_EOL;
?>
<?php
/**
* Ejemplo 3:
*/
class Text
{
protected $string;
public function __construct($string) { $this->string = $string; }
public function getString() { return $this->string; }
}
class UpperCase
{
protected $text;
public function __construct($text) { $this->text = $text; }
public function getString() { return strtoupper($this->text->getString());}
}
class Bold
{
protected $text;
public function __construct($text) { $this->text = $text; }
public function getString() { return '<strong>' . $this->text->getString() . '</strong>';}
}
class Underline
{
protected $text;
public function __construct($text) { $this->text = $text; }
public function getString() { return '<u>' . $this->text->getString() . '</u>';}
}
$text = new Text('Hola Amigos');
echo $text->getString() . PHP_EOL;
$text = new UpperCase(new Text('Hola Amigos'));
echo $text->getString() . PHP_EOL;
$text = new Bold(new UpperCase(new Text('Hola Amigos')));
echo $text->getString() . PHP_EOL;
$text = new Underline(new Bold(new UpperCase(new Text('Hola Amigos'))));
echo $text->getString() . PHP_EOL;
?>
<?php
/**
* Ejemplo inicial usando interfaces
*
* Escribo una interface con el o los
* métodos comunes que deben tener todas las
* decoraciones y el objeto a ser decorado.
*/
interface IDecorator
{
public function getDamage();
}
/**
* Implemento la interface en la clase que voy a decorar
*/
class Damage implements IDecorator
{
protected $name;
protected $damagePoints = 10;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getDamage()
{
return $this->damagePoints;
}
}
/**
* Creo una clase abstracta con las funcionalidades
* comunes que tendrán los decoradores, para evitar
* la duplicación de codigo.
*
* También implemento la interface IDecorator.
*/
abstract class StoneDecorator implements IDecorator
{
protected $damage;
protected $damagePoints;
/**
* Uso un Typehint para forzar que el parámetro
* que vaya a pasar cumpla con la interface IDecorator
*/
public function __construct(IDecorator $damage)
{
$this->damage = $damage;
}
public function getDamage()
{
/**
* Como estamos seguro que se esta usando la interface IDecorator
* Podemos estar seguros que el método "getDamage()" va a existir
*/
return $this->damage->getDamage() + $this->damagePoints;
}
public function __call($method, $args)
{
return call_user_func_array(array($this->damage, $method), $args);
}
}
/**
* Defino las decoraciones, extendiendo la clase abstracta que implementa
* la interface IDecorator.
*/
class StoneOfFire extends StoneDecorator { protected $damagePoints = 2; }
class StoneOfWind extends StoneDecorator { protected $damagePoints = 7; }
// Ahora si los ejemplos
$damage = new StoneOfFire(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
$damage = new StoneOfWind(new Damage('Rocky'));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
$damage = new StoneOfFire(new StoneOfWind(new Damage('Rocky')));
echo 'Un golpe de ' . $damage->getName() . ' es de ' . $damage->getDamage() . ' puntos' . PHP_EOL;
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment