Last active
October 12, 2016 13:49
-
-
Save mpratt/5572524 to your computer and use it in GitHub Desktop.
Patrones de Diseño: Decorador (Decorator)
http://www.michael-pratt.com/blog/14/Patrones-de-Diseno-Decorador-Decorator/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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