160 likes | 318 Views
Patrón Composite Tipo : Estructural, objeto Nivel : Componente Propósito : Desarrollar una forma flexible de crear jerarquías en estructura de árbol de una complejidad arbitraria, permitiendo a la vez que todos los elementos de la estructura funcionen con una interfaz uniforme.
E N D
Patrón Composite • Tipo: Estructural, objeto • Nivel: Componente • Propósito: Desarrollar una forma flexible de crear jerarquías en estructura de árbol de una complejidad arbitraria, permitiendo a la vez que todos los elementos de la estructura funcionen con una interfaz uniforme. • Aplicabilidad: Utilice el patrón Composite cuando: • Haya un componente modelado como una estructura rama-hoja (o parte-todo, o contenedor-contenido). • La estructura pueda tener cualquier nivel de complejidad y sea dinámica. • Desee tratar uniformemente la estructura del componente, utilizando operaciones comunes en toda la jerarquía. • Descripción: Este modelo permite tratar una colección de objetos idénticos (las partes) como una entidad (el todo). Normalmente estas estructuras deben ser flexibles y fáciles de utilizar. Los usuarios deben poder modificar la estructura conforme se ejecuta la aplicación, introduciendo o eliminando partes para adaptarla a sus necesidades. • La estructura se compone de un componente, una hoja y una clase Composite. • El Componente(Component) base proporciona el modelo principal, el cual define los métodos estándar o las variables que se utilizan en todos los objetos del patrón Composite. • Las clases Hoja contienen el comportamiento final. Es decir, representan partes del Compuesto, pero solo aquellas que no pueden contener a otros componentes. • Las clases Compuesto (Composite), o ramas, pueden tener otros componentes, permitiendo la extensibilidad de la estructura compuesta.
Diagrama de Clases Patrón Composite Figura 3.4 (página 162) del libro “Patrones de Diseño Aplicados a Java”.
Implementación: • Como se ve en la figura 3.4 el Patrón tiene 3 elementos: • Componente (Component): la interface en la que se definen los métodos disponibles para todas las partes de la estructura. Como cualquier interface, es una clase abstracta o sea no instanciable. • Compuesto (Composite): esta clase implementa la interface Componente y queda definida por los componentes que alberga; está compuesta por sus componentes. La clase Compuesto soporta un grupo dinámico de objetos Componente, y por ello tiene una serie de métodos para insertar instancias de Componente en la colección y para eliminar instancias de Componente de la colección. Las clases Compuesto también son denominadas ramas o clases contenedor. • Hoja (Leaf): la clase que también implementa la interface Componente. La diferencia entre una clase Hoja y una clase Compuesto es que Hoja no contiene referencias a otros objetos Componente. Las clases Hoja representan el nivel más bajo de la estructura.
Demo con fuentes java A continuación se visualiza el Diagrama de Clases de la Demo sin clases adicionales y su explicación para luego imprimirse el archivo composite.gif que fue bajado junto con los codigos fuente en java del sitio indicado en el libro "Patrones de Diseño aplicadosa Java" de Stelting-Maassen, editorial Pearson-Prentice Hall, edicion 2003. Este archivo contiene el diagrama de clases de la Demo del Composite. El programa java “main” es el RunPattern.java y cuando se corre por 1ra vez genera un archivo con una estructura de datos en forma de arbol que se muestra en otra diapositiva para luego explicar el mecanismo de funcionamiento en detalle y lograr unas conclusiones que ayudan a comprender cabalmente al Patrón Composite.
Diagrama de clases sin clases adicionales • Hay 2 clases “Compuesto”: Task y Project • Project, Deliverable y Task implementan la Interface (ver que la relación es de Realización) ProjectItem: NOTAR que NO es relación de herencia.
Diagrama de clases sin clases adicionales: explicación • En el diagrama de clases se muestra cómo utilizar el patrón Composite para calcular el tiempo necesario para completar un proyecto o alguna parte del mismo. Las 4 partes principales son: • Deliverable (entregable): la clase que representa un producto final de una tarea finalizada. • Project (proyecto): la clase utilizada como raíz del objeto compuesto y que representa el proyecto completo. • ProjectItem (item de proyecto): la interfaz que describe la funcionalidad común de todos los elementos que son parte de un proyecto. Aquí se define el método getTimeRequired. Pero es una clase abstracta, no instanciable. • Task (tarea): la clase que representa una colección de acciones que hay que ejecutar. Cada tarea contiene una colección de objetos ProjectItem.
miProyecto:Project tarea1:Task tarea2:Task tarea3:Task deliverable1:Deriverable timeRequired:11.0 timeRequired:=7.5 timeRequired:=3.2 tarea11:Task tarea21:Task deliverable31:Deliverable timeRequired:=2.5 timeRequired:=1.8 tarea12:Task tarea22:Task timeRequired:=1.4 timeRequired:=5.0 deliverable11:Deliverable tarea23:Task timeRequired:=17.5
Mecanismo de funcionamiento (clase RunPattern.java): Demo del Patron de Diseño COMPOSITE Este main, en primer lugar, crea una estructura de datos como la mostrada en la pagina anterior y para hacer eso llama a un metodo que está en la clase DataCreator.java, que también graba estos datos en un archivo data.ser. Luego llama a un método que está en la clase DataRetriever (Recuperador de Datos) que consigue apuntar al objeto miProyecto creado como archivo. Luego le dice a miProyecto que ejecute su método getTimeRequired, o sea que a un proyecto se le dice: “decime cuanto tiempo te falta para que finalices”. El objeto miProyecto es de la clase Project y contiene, en su interior, 4 objetos: tarea1, tarea2, tarea3 y deliverable1. Cualquier objeto tareaX es una instancia de la clase Task mientras que cualquier objeto deliverableX es una instancia de la clase Deliverable (parte entregable). Cuando se le envía el mensaje getTimeRequired al objeto miProyecto éste se lo vuelve a enviar a cada uno de los objetos que están contenidos dentro de miProyecto. El objeto deliverable1 devolverá un valor nulo a este mensaje mientras que cada objeto tarea1, tarea2 y tarea3 que, a su vez, son objetos “contenedores” harán lo siguiente: Cuando tarea1 recibe el mensaje getTimeRequired primero suma su propio tiempo requerido de 11.0 y luego retransmite el mismo mensaje hacia cada uno de los objetos que tarea1 contiene que son: tarea11, tarea12 y deliverable11. Cuando tarea11 recibe el mensaje getTimeRequired suma su propio tiempo requerido de 2.5 y como no contiene a ningún otro objeto retorna el control. Cuando tarea12 recibe el mensaje getTimeRequired suma su propio tiempo requerido de 1.4 y como no contiene a ningún otro objeto retorna el control. Cuando deliverable11 recibe el mensaje getTimeRequired devuelve un valor nulo. Cuando tarea2 recibe el mensaje getTimeRequired primero suma su tiempo propio requerido de 7.5 y luego retransmite el mensaje hacia cada uno de los objetos que tarea2 contiene en su interior: tarea21, tarea22 y tarea23. Cuando tarea21 recibe el mensaje getTimeRequired suma su propio tiempo requerido de 1.8 y como no contiene a ningún otro objeto retorna el control. Cuando tarea22 recibe el mensaje getTimeRequired suma su propio tiempo requerido de 5.0 y como no contiene a ningún otro objeto retorna el control. Cuando tarea23 recibe el mensaje getTimeRequired suma su propio tiempo requerido de 17.5 y como no contiene a ningún otro objeto retorna el control. Cuando tarea3 recibe el mensaje getTimeRequired primero suma su propio tiempo requrido de 3.2 y luego retransmite el mensaje hacia cada uno de los objeto que tarea3 contiene en su interior: deliverable31. Cuando deliverable31 recibe el mensaje getTimeRequired devuelve un valor nulo.
Conclusiones: • Se podría enviar el mensaje getTimeRequired al objeto tarea2 en cuyo caso nos daría el tiempo requerido para finalizar las tareas de tarea2 y de las incluidas en tarea2 ya que es un objeto compuesto. • Se podría enviar el mensaje getTimeRequired a la tarea3 que no tiene otras tareas incluidas dentro de su interior y devolvería directamente el valor 3.2 (valor del atributo timeRequired del objeto tarea3). • O sea que se trata de igual manera a un objeto simple que a un compuesto, mientras sepa contestar getTimeRequired (dame El Tiempo Requerido para finalizarte). • Se pone de manifiesto el hecho de que la interface es una clase abstracta porque no existen instancias de ProjectItem y para lo único que está es para definir que tanto los compuestos (para este ejemplo Task y Project) como los nodos (Deliverable) “hereden” el comportamiento getTimeRequired sin hacer uso de la herencia sino de la composición. • Sin embargo en cada clase “se implementa” diferentemente el getTimeRequired ya que mientras Deliverable siempre devuelve un valor nulo, Project no suma un valor “propio” sino que devuelve la sumatoria de sus compuestos y que Tarea devuelve la suma de su valor propio más la sumatoria de sus compuestos.
Conclusiones (continuación): • La clase Contact está solamente para mostrar que cada tarea (Task) tiene un “responsable” o “contacto” y no nos referimos demasiado a esta clase porque no interviene como “compuesto” ni como “componente” que son las clases más significativas en este patrón. • Se debe admirar la magia del mecanismo que está fundamentado en como están estructuradas las clases por eso este patrón es del tipo Estructural. Cada objeto si es un componente no compuesto (llamado también hoja o sea que es una tarea simple sin componente alguno) devuelve un valor coherente y si es un compuesto pone su participación (en tiempo) y luego manda a que lo hagan sus componentes. Todo esto SIN usar de ninguna sentencia IF. • Ningún objeto tiene una “vista panorámica” de la estructura del árbol que representa a cada proyecto. Solamente sería apreciada de esa manera por algún “cliente” totalmente exterior a la estructura. Cada objeto compuesto solamente mira en su interior de cuales objetos está compuesto y es como si no le interesase para nada saber si dichos objetos son simples o compuestos. Cada objeto compuesto, entonces, solo puede “mirar”, a lo sumo, a la rama del árbol que –eventualmente- el mismo objeto compuesto representa.
Caso de estudio: Diseño de un Editor de Documentos Carácter carácter espacio imagen compuesto (fila) G g Nota: este caso de estudio es tratado en el libro “Patrones de Diseño” de Gamma, Helm, Johnson y Vlissides” Capítulo 2 Compuesto (columna)