Mi granito de java: Composite

Google+ Badge

miércoles, 1 de junio de 2011

Composite

El patrón Composite sirve para construir algoritmos u objetos complejos a partir de otros más simples y similares entre sí, gracias a la composición recursiva y a una estructura en forma de árbol. Dicho de otra forma, permite construir objetos complejos componiendo de forma recursiva objetos similares en una estructura de árbol. Esto simplifica el tratamiento de los objetos creados, ya que al poseer todos ellos una interfaz común, se tratan todos de la misma manera.

Este patrón busca representar una jerarquía de objetos conocida como “parte-todo”, donde se sigue la teoría de que las "partes" forman el "todo", siempre teniendo en cuenta que cada "parte" puede tener otras "parte" dentro.

Se debe utilizar este patrón cuando:
  • Se busca representar una jerarquía de objetos como “parte-todo”.
  • Se busca que el cliente puede ignorar la diferencia entre objetos primitivos y compuestos (para que pueda tratarlos de la misma manera).

Diagrama UML


Component: implementa un comportamiento común entre las clases y declara una interface de manipulación a los padres en la estructura recursiva.
Leaf: representa los objetos “hoja” (no poseen hijos). Define comportamientos para objetos primitivos.
Composite: define un comportamiento para objetos con hijos. Almacena componentes hijos. implementa operaciones de relación con los hijos.
Cliente: manipula objetos de la composición a través de Component.
Los clientes usan la interfaz de Component para interactuar con objetos en la estructura Composite. Si el receptor es una hoja, la interacción es directa. Si es un Composite, se debe llegar a los objetos “hijos”, y puede llevar a utilizar operaciones adicionales.

Ejemplo

Vamos a realizar un ejemplo de un Banco. Un banco puede tener muchos sectores: Gerencia, Administrativo, RRHH, Cajas, etc. Cada uno de estos sectores tendrá empleados que cobran un sueldo. En nuestro caso utilizaremos el Composite para calcular la sumatoria de sueldos de la empresa. Para ello definimos la Interface y el Composite.

En la clase Composite está todo el secreto del patrón: contiene una colección de hijos del tipo ISueldo que los va agregando con el método agrega(ISueldo) y cuando al composite le ejecutan el getSueldo() simplemente recorre sus hijos y les ejecutas el método. Sus hijos podrán ser de 2 tipos: Composite (que a su vez harán el mismo recorrido con sus propios hijos) u Hojas que devolverán un valor.
En nuestro ejemplo hay varios sectores, solo pongo uno para no llenar de pics el ejemplo. Pero todos son muy parecidos: la única relación que tienen con el composite es que heredan de él.
Ahora veamos el caso del empleado que trabaja en el banco (sería una hoja):

Listo, ahora veamos la forma de concatenar todo. Yo lo hice en el Main (que vendría a representar al cliente), pero en realidad el armado del banco no siempre lo debe hacer el cliente. De hecho, podríamos utilizar un patrón creacional para que nos ayude en el armado.

El banco se compone de varios sectores, los cuales pueden tener personas o más sectores adentro.


Consecuencias.
  • Define jerarquías entre las clases.
  • Simplifica la interacción de los clientes.
  • Hace más fácil la inserción de nuevos hijos.
  • Hace el diseño más general.
  • Si la operación es compleja, puede ensuciar mucho el código y hacerlo ilegible.
Temas a tener en cuenta

Hay muchas formas de llevar a cabo este patrón. Muchas implementaciones implican referencias explicitas al padre para simplificar la gestión de la estructura.
Si el orden de los hijos provoca problemas utilizar Iterator.Para borrar elementos les recomiendo que un objeto elimine a sus hijos.
La mejor estructura para almacenar elementos depende de la eficiencia: si se atraviesa la estructura con frecuencia se puede dejar información en los hijos.
Publicar un comentario en la entrada