Patrón de diseño Decorator en PHP5

Patrón de diseño Decorator en PHP5 

Patrón Decorator responde a la necesidad de agregar funcionalidad a un objeto por medio de la asociación de clases. Es un objeto con el que se puede ejecutar funcionalidades de varias clases a la vez.

"Esto nos permite no tener que crear sucesivas clases que hereden de la primera incorporando la nueva funcionalidad, sino otras que la implementan y se asocian a la primera." [1]



Clasificación del patrón

Estructural.

Intención o problema que soluciona


"Supongamos que tenemos una clase existente Ventana y queremos añadirle funcionalidad para que muestre un borde alrededor. Podemos crear una subclase VentanaConBorde que herede de Ventana. Hasta aquí todo bien, pero supongamos que surge la necesidad de crear una ventana que muestre un pequeño botón de ayuda con un signo de interrogación (?) en su parte superior." [1]

Entonces tenemos las siguientes opciones:

1. Crear otra subclase de Ventana: VentanaConBotónDeAyuda.

Problema: No cubre la necesidad de tener ventanas con bordes y botón de ayuda a la vez.

2. Crear una subclase de VentanaConBorde: VentanaConBordeYBotonDeAyuda.

Problema: No tenemos una ventana con botón de ayuda y sin borde.
3. Crear clases para todas las combinaciones posibles de funcionalidades.


Problema: Con este ejemplo tendríamos cuatro clases: Ventana, VentanaConBorde, VentanaConBotonDeAyuda y VentanaConBordeYBotonDeAyuda; con tres funcionalidades tendríamos ocho clases y con cuatro, ¡dieciséis!.

Aplicabilidad
  1. Añadir objetos individuales de forma dinámica y transparente.
  2. Responsabilidades de un objeto pueden ser retiradas.
  3. Cuando la extensión mediante la herencia no es viable.
  4. Hay una necesidad de extender la funcionalidad de una clase, pero no hay razones para extenderlo a través de la herencia.
  5. Hay la necesidad de extender dinámicamente la funcionalidad de un objeto y quizás quitar la funcionalidad extendida. [1]


Código de Ejemplo en PHP5

  1. <?php  
  2. interface iCoffee {  
  3.   public function getBaseCost();  
  4. }  
  5.          
  6. class Coffee implements iCoffee {  
  7.   protected $_baseCost = 0;  
  8.   public function getBaseCost()  
  9.   {  
  10.     return $this->_baseCost;  
  11.   }  
  12. }  
  13.   
  14. class BlackCoffee extends Coffee {  
  15.   public function __construct()  
  16.   {  
  17.     $this->_baseCost = 5;  
  18.   }  
  19. }  
  20.   
  21. abstract class CoffeeDecorator implements iCoffee {  
  22.   protected $_coffee;  
  23.   public function __construct(iCoffee $Coffee)  
  24.   {  
  25.      $this->_coffee = $Coffee;  
  26.   }  
  27. }  
  28.   
  29. class WithCream extends CoffeeDecorator {  
  30.   public function getBaseCost()  
  31.   {  
  32.     return $this->_coffee->getBaseCost() + 1.5;  
  33.   }  
  34. }  
  35.   
  36. class WithMilk extends CoffeeDecorator {  
  37.   public function getBaseCost()  
  38.   {  
  39.      return $this->_coffee->getBaseCost() + 4;  
  40.   }  
  41. }  
  42.   
  43. class WithChocolate extends CoffeeDecorator {  
  44.   public function getBaseCost()  
  45.   {  
  46.     return $this->_coffee->getBaseCost() + 5;  
  47.   }  
  48. }  
  49.   
  50. $coffee = new WithChocolate(new WithMilk(new WithCream(new BlackCoffee())));  
  51. echo 'El precio del cafe es: $' . $coffee->getBaseCost();  

Otros artículos sobre Patrones
  1. Patron Singleton en PHP
  2. Patrón de diseño Decorator en PHP
  3. Patrón Simple Factory en PHP
  4. Patrón Registry en PHP
  5. Patrón clásico de diseño web Modelo Vista Controlador (MVC) en PHP

Referencias bibliográficas

[1] Colaboradores de Wikipedia. Decorator (patrón de diseño) [en línea]. Wikipedia, La enciclopedia libre, 2009 [fecha de consulta: 9 de septiembre del 2009]. Disponible en <http://es.wikipedia.org/w/index.php?title=Decorator_(patr%C3%B3n_de_dise%C3%B1o)&oldid=27813809>.

3 comentarios:

  1. por que tu codigo no funciona si le pones una funcion mas a la interface??

    ResponderEliminar
  2. amigo arley se le saluda, algo de tiempo sin tener nuestros debates o mas bien sus grandes respuestas a mis preguntas y este no deja de ser el caso, resulta que estaba viendo un poco su entrada del patron decorator y creo que mas claro no pudo ser pero hay algo que me intriga, en cuanto a esta porcion de codigo

    abstract class CoffeeDecorator implements iCoffee {
    protected $_coffee;
    public function __construct(iCoffee $Coffee)
    {
    $this->_coffee = $Coffee;
    }
    }

    si te fijas estas implementando la interface en la clase CoffeDecorator, segun tengo entendido y corrijame si estoy equivocado las interfaces son un contrado de implementacion donde cada metodo declarado en la interface debe de estar definido en la clase que lo implementa en este caso note que no esta definido este sino que lo pasa como parametro por medio del BlackCoffe, entonces para que implementar la interface en la clase CoffeeDecorator?? para obligar a los que extiendan de esta implemente el metodo getBaseCost??
    por supuesto hice las pruebas pertinentes a su ejemplo y funciona de maravilla pero me surgieron estas dudas, saludos y felicitaciones por su gran blog

    ResponderEliminar
  3. carlos, fijate bien pero la clase que implementa la interfaz es una clase abstracta, no hace falta que implemente los metodos del mismo, pero si las clases que vallan a extender esa clase abstracta, saludos!

    ResponderEliminar