domingo, 21 de julio de 2013

Ejemplo Patrón de Diseño Decorator

Llegamos a la penúltima entrada sobre el tema de patrones de Diseño, en esta ocasión trabajaremos un nuevo ejemplo pero enfocado en el Patrón Decorator.......

Así como en la mayoría de los trabajados, vamos a apoyarnos en el libro Head First Design Patterns para crear nuestro ejemplo, un ejemplo sencillo con una problemática por resolver, al final compartiré un enlace donde se podrá descargar el proyecto Java que trabajaremos...


¿Que es?

El Patrón Decorator Permite agregar funcionalidades y responsabilidades a objetos de forma dinámica y transparente para el usuario, esto se realiza por medio de relaciones con otras clases extendiendo su funcionalidad al incorporar las de las clases asociadas, de esta forma el patrón no es dependiente de la Herencia ya que aunque esta puede jugar un papel importante, prevalece el uso de conceptos como la composición al momento de definir comportamientos....



Como vemos en el diagrama de clases, tenemos una SuperClase de la cual heredan clases concretas y las clases Decoradoras que a su vez también pueden ser clases padre de clases decoradoras Concretas...... ¿Que?.....

¿Pero si dijimos que el patrón no es dependiente de la herencia porque hablamos de SuperClases?

La pregunta anterior es muy común, ya que puede llegar a ser muy confusa la definición, sin embargo la respuesta es muy simple, con el Decorator la herencia es requerida ya que los decoradores deben tener el mismo tipo de los objetos a decorar pero no se utiliza la Herencia para lograr el comportamiento....... el comportamiento se da al realizar la composición de decoradores con los componentes concretos.....(Cuando Hablamos de comportamiento, nos referimos a las nuevas funcionalidades que usamos...)

Si se basará en la herencia el comportamiento solo se definiría estáticamente en tiempo de compilación dependiendo de lo que las clases padres hereden, a demás todas las subClases deben heredar comportamientos que puede que no vayan a utilizar.....

El Problema.

Un restaurante de comidas rápidas ofrece 3 tipos de combos (Combo Básico, Combo Familiar, Combo Especial) cada combo tiene características diferentes en cuanto a cantidad, porciones, salsas entre otros, el restaurante también ofrece la posibilidad de aumentar el pedido mediante diferentes porciones adicionales (Tomate, Papas, Carne, Queso), se desea crear un sistema de pedidos que permita al usuario seleccionar el combo deseado, así como armar su propio pedido con las porciones adicionales, el sistema deberá informar sobre el pedido del usuario y el valor total del mismo.

La Solución.

En el problema nos están solicitando algo puntual, fácilmente deducimos que tenemos una familia de Combos en la que podemos usar la herencia, pero si atacáramos nuestro problema solo con este concepto, entonces tendríamos que crear clases concretas por cada posible combinación de porciones adicionales, tal vez esto no seria problema y el sistema funcione, pero si queremos realizar varias combinaciones para crear nuevos pedidos tendríamos que entrar a modificar el código fuente y luego ejecutar nuevamente la aplicación para que los cambios puedan ser visualizados.... por esta razón anteriormente dijimos que usando la herencia el comportamiento solo se definiría estáticamente basados en lo heredado por las clases Padre....

La solución que nos da el patrón Decorator es solo utilizar la herencia para que las clases Decorator tengan el mismo tipo de los objetos a decorar y utilizaremos la composición para determinar el comportamiento de forma dinámica y en tiempo de ejecución basados en concepto de "Usa" relacionando los decoradores con los componentes concretos, así no modificaríamos la lógica de las clases existentes cada vez...... Veamos....

La Aplicación.


Crearemos nuestro sistema ajustándonos al diagrama de clases del patrón, tenemos una SuperClase Combo que representa los combos de comidas rápidas disponibles de la cual heredan los tipos ComboBasico, ComboFamiliar y ComboEspecial, también hereda de el las clases Decorator, en este caso tenemos la clase de Adicionales como el decorador y a su vez las hijas que corresponden a cada porción, siendo estas las clases decoradoras concretas....

Vamos a explicar la Aplicación agrupándola en sus 3 paquetes: Componentes, Decoradores y Principal...

Componentes.

Este paquete contiene la Jerarquía de componentes del patrón, aquí tenemos la SuperClase Combo y sus hijas concretas, el Combo es una clase Abstracta que define una descripción que cada subClase definirá (de que se compone el combo), así como también el método abstracto valor que sera definido por cada subClase que lo implemente.
public abstract class Combo {
 
 String descripcion = "";
 
 public String getDescripcion() 
 {
  return descripcion;
 }

 public abstract int valor();

}

Las estructura de las clases concretas también es simple, definirán el precio del combo correspondiente y asignaran una descripción. (Cada Clase es igual...)
public class ComboBasico extends Combo{

 public ComboBasico() {
  descripcion="Porcion de Papas Fritas, " +
   "salsa, queso, amburgueza sencilla, gaseosa";
 }
 
 @Override
 public int valor() {
  return 6200;
 }
}

Decoradores.

Los Decoradores en este caso serán las porciones adicionales, tenemos una clase AdicionalesDecorator que es el decorador principal del cual implementaran los decoradores concretos, esta clase es hija de la clase Combo y proporciona un método abstracto descripcion() para anexar a la descripción del combo, la porción seleccionada por el usuario...
public abstract class AdicionalesDecorator extends Combo{

 public abstract String getDescripcion();
}

Cada Decorador concreto implementa el método getDescripcion(), agregando a la descripción la porción seleccionada por el usuario, también implementa el método valor() de la clase Combo, en el cual se agrega al valor del combo, el precio de la porción....... como vemos en estos decoradores concretos se aplica la composición en el momento que creamos el objeto combo (la clase Combo es abstracta por lo tanto no puede ser instanciada directamente, por lo tanto el objeto que llega como parámetro al constructor se creó previamente por medio de polimorfismo)....
public class Carne extends AdicionalesDecorator{

 Combo combo;
 
 public Carne(Combo combo)
 {
  this.combo=combo; 
 }
 
 @Override
 public String getDescripcion() {
  return combo.getDescripcion()+" , Porcion de Carne";
 }

 @Override
 public int valor() {
  return 2500+combo.valor();
 }
}

Principal.




Finalmente en el paquete principal tenemos la clase donde se ejecuta el programa y la ventana que representa el Menú de Selección desde el cual el usuario puede seleccionar el Combo y las porciones a pedir, al enviar el pedido el sistema de forma dinámica por medio del patrón Decorator valida las combinaciones solicitadas y calcula el precio Total del pedido.


Y listo, al aplicar el patrón pudimos crear un menú de comidas que puede ser construido por el usuario, sin necesidad de modificar cada vez el código fuente ya que el armado del menú se realiza en tiempo de ejecución gracias al Decorator!!!


Conclusiones.

Como vemos el patrón nos facilita enormemente el trabajo en este tipo de problemáticas  imaginen tener que usar solo la herencia para crear un Menú que cumpla con las necesidades de cada cliente, cuantas combinaciones se tendrían que realizar por cada posible combinación, en cambio con el patrón tan solo necesitamos las clases Bases y los decoradores, gracias a la lógica aplicada, las combinaciones se realizan solas....

La lógica del patrón actúa como envoltorios dependiendo de los posibles tipos de combos y adicionales seleccionadas, si queremos un combo familiar con papas extra entonces se crea esta agrupación, si además escogemos una porción de queso entonces dicha porción es agregada a la anterior...

Cuando usamos este patrón reducimos las posibilidades de generar errores o defectos secundarios no deseados, ya que si queremos añadir nuevas funcionalidades, agregamos nuevo código sin modificar el existente...

Con el Patrón los diseños son resistentes al cambio y lo suficientemente flexibles como para satisfacer necesidades cambiantes.

El patrón a demás de utilizar la herencia y la composición también aplica conceptos de polimorfismo que pueden ser evidenciados en el código fuente..

Como en todo la practica es fundamental, por eso los invito a repasar el Patrón y descargarlo para un mayor entendimiento.


Referencias.

Head First Design Patterns




Descarga.

El ejemplo es muy básico y simple, para entenderlo mejor les dejo el link de descarga para que lo prueben ;)....está en Eclipse pero si usas NetBeans te interesará esta entrada con un vídeo paso a paso de como abrirlo en el......... [recuerden que es gratis.....nada cuesta opinar, compartir o agradecer :)]


También te podría Interesar. 


¿Hay algo que quieras anexar o comentar sobre esta entrada?  no dudes en hacerlo.....y si te gustó, te invito a compartir y Suscribirte ingresando al botón "Participar en este sitio" para darte cuenta de mas entradas como esta ;)

32 comentarios:

  1. muy claro explicados todos los patrones gracias por compartir!
    NO CUESTA NADA AGRADECER GENTE y menos buenos articulos y sobre todo claros y consciso.

    ResponderEliminar
    Respuestas
    1. Hola Muchas Gracias, es algo muy facil de hacer que la mayoria de las veces se omite, pero almenos con comentarios como este uno se motiva a continuar... ;) Gracias por comentar, Un Saludo y me alegra que te gustara

      Eliminar
  2. Muy bueno!!!! Y si este ejemplo lo quisiera hacer con una BD???

    ResponderEliminar
    Respuestas
    1. Hola, que pena no habia visto tu comentario, y claro que se puede, seria lo mismo, lo que cambia es de donde obtienes la información.....eso si, tendrias que tener cuidado de no realizar tantas transacciones o llamados a la BD, si es algo pequeño no hay problema, pero si es algo grande depronto pueda bajar el rendimiento..... para evitar eso puedes hacer un unico llamado a la BD, cargar los datos y procesarlos como listas y con estas es con las que trabajarias.... un saludo y gracias por comentar....

      Eliminar
  3. ah no! yo me lo sabía con combinaciones del café! ;)
    Gracias Cristian!
    La verdad que muy clara y entretenida tu redacción!!

    Saludos!
    Jose Luis

    ResponderEliminar
    Respuestas
    1. jajaja ahi ves que aplica para cualquiera ;) muchas gracias por comentar, y lamento la demora (y)

      Eliminar
  4. Hola, te felicito es un ejemplo muy bien desarrollado, me aclaró muchas dudas y gracias por compartir el codigo, funciona a la perfección, eso ayuda mucho para entenderlo mejor. Ojalá cada vez haya más personas que les complazca compartir sus conocimientos para que principiantes como yo, sigamos aprendiendo.

    ResponderEliminar
    Respuestas
    1. Con gusto, me alegra que te sirviera y esa es la idea, compartir el conocimiento ;).......gracias por comentar (y)

      Eliminar
  5. Ufff, esto me viene genial! A penas hace medio año arranqué con java en la universidad y ya me están matando con muchos de estos patrones!!! Por suerte, veo que desarrollaste varios, me apunto a estudiarlos a todos. Están muy entendibles, y los ejemplos van de diez. Encima con links y todo... fenomenal, te pasaste! Muchas gracias!!!

    Saludos desde Argentina!

    ResponderEliminar
    Respuestas
    1. Hola, esa es la idea y me alegra que te pudiera servir... muchos exitos con la carrera!!!

      Eliminar
  6. Excelentes ejemplos y explicaciones!! Muchas gracias por la dedicación. Saludos desde Uruguay.

    ResponderEliminar
    Respuestas
    1. Hola, me alegra mucho que te sirva, saludos desde Colombia!!!

      Eliminar
  7. por que no hacer la clase combo una interface que implemente las subclases???
    O sea, no es estrictamente necesario tener una interface para aplicar el patron decorator???

    ResponderEliminar
  8. Excelente ejemplo Cristian! Muy útil y sencillo de entender.

    ResponderEliminar
  9. Muchas gracias por la explicación, habia leído sobre este patrón, pero no me quedaba claro por que usaba la herencia, si precisamene la consideraba estática. Es la primera vez que llego al sitio y seguramente va a favoritos.
    Saludos.
    Mauricio desde Córdoba, Argentina.

    ResponderEliminar
    Respuestas
    1. Hola Mauricio, me alegra que te sirva y espero que ese seguramente se haga seguro jeje un saludo desde Colombia.

      Eliminar
  10. Tengo una duda, ¿Como haria para quitar un decorator que ya haya agregado al combo?
    PD: excelente articulo me ayudo a entenderle al patron.

    ResponderEliminar
  11. excelente! muy claro!

    ResponderEliminar
  12. buena explicacion sobre el patron decorator

    ResponderEliminar
  13. Excelente explicacion. Muy clara y precisa.

    ResponderEliminar
  14. Está muy bien la explicación, acá me gustaría hacerte un aporte constructivo.

    Si revisas bien, la clase Combo se repite en cada una de las subclases de decorador y en el diagrama UML tienes que el AdicionalesDecorator es quien realmente hace referencia al Combo, así que Combo debería ser un atributo protected sobre la clase AdicionalesDecorator en la cual se pasaría como parámetro en el constructor y se elimina del resto de las subclases.

    ResponderEliminar
  15. Muy buena explicacion. Muchas gracias por tus aportes.

    ResponderEliminar
  16. Excelente aporte muchas gracias por su concepto y ejemplo.
    Saludos cordiales.

    ResponderEliminar
  17. Cristian, muy buen post ante que nada.
    Te quería consultar lo siguiente en relación a este patrón, supongamos que yo tengo la Clase IMDBPeliculas, cuya funcionalidad es obtener datos en referencia a una película desde el Servidor IMBD. Supongamos que a futuro podríamos tener una fuente de datos de película similar a IMDB pero desde otros proveedor (Amazon, Netflix, etc.). Debería ser posible agregar a nuestro modelo estas nuevas funcionalidades indicando en nuestro Diseño un mecanismo claro para definir cuál proveedor tiene prioridad sobre otros.
    Serviría para este caso implementar el Patron Decorator utilizando como Componente Contreto nuestra Clase IMDBPeliculas e ir agregando a nuestra Clase Decorator , subclases como AmazonPeliculas ( decorardor concreto A) y NetflixPeliculas (decorador concreto B).
    Muchas Gracias. Un saludo.

    ResponderEliminar
  18. gracias querido! muy util tu explicacion! estudiando para un examen de la facultad me sirvio.

    ResponderEliminar
  19. Gracias, por todos los patrones. Me dejas muy claro cada concepto, Y este ejemplo ha sido muy bueno. En mi caso lo aplicare para una aplicación de helados al cual se le agrega productos adicionales, etc.
    Gracias totales.

    ResponderEliminar
  20. Excelente aporte gracias!!

    saludos desde Bolivia.

    ResponderEliminar
  21. Excelente artículo. He leído todo lo referente a patrones. Muchas gracias por tu disposición para hacer aportes tan bien elaborados.

    ResponderEliminar
  22. Muy buen artículo. Sólo haría unas pequeñas modificaciones al código de ejemplo: instanciaría los Componentes Concretos en verificaSeleccion() y allí aprovecharía el método de acceso para obtener la descripción (evitando cablear y repetir código) dejando en el actionPerformed sólo el método enviarPedido.

    ResponderEliminar

Eres libre de realizar cualquier comentario, desde que pueda ayudar con gusto lo atenderé, y si es un critica, bienvenida sea!!!