Qué es el patron de diseño Composite

Qué es el patron de diseño Composite

Siguiendo nuestro curso de programación hoy veremos el patrón Composite. El patrón estructural Composite permite componer objetos en estructuras arbóreas para representar jerarquías de todo-parte, de modo que los clientes puedan tratar a los objetos individuales y a los compuestos de manera uniforme.

uml_composite

Aplicaciones

Utilícese el patrón Composite para:

  • Representar jerarquías de parte-todo.
  • Que los clientes traten por igual los objetos individuales y los compuestos.

Ventajas

  • Permite jerarquías de objetos tan complejas como se quiera. Allá donde el cliente espere un objeto primitivo, podrá recibir un compuesto y no se dará cuenta
  • Simplifica el cliente. Al eliminar el código para distinguir entre unos y otros
  • Se pueden añadir nuevos componentes fácilmente.

Desventajas

Podría hacer el diseño demasiado general, especialmente cuando queremos restringir los componentes que pueden formar parte de un compuesto determinado.

Esquema

Vamos a explicar el esquema mediante un ejemplo. Supongamos un editor de dibujo que permite realizar dibujos compuestos de elementos simples como líneas, rectángulos… u otros dibujos, ¿Cómo evitamos que los clientes tengan que distinguir entre unos y otros?

esquema_composite

  • Component (Grahic). Declara la interfaz común. También declara operaciones para acceder a los hijos (opcional) Define una interfaz para acceder al padre. Implementa el comportamiento predeterminado que es común a todas las clases.
  • Leaf (Rectangle, Line, Text…)
  • Composite (Picture). Almacena sus componentes hijos e implementa las operaciones relacionadas con los hijos.
  • Client: Manipula los objetos de la composición a través de la interfaz de Component.

Ejemplo

Vamos hacer otro ejemplo en código. Supongamos que tenemos una clase abstracta AbstractArchivo que es la implementada por la clase Archivo y la clase Directorio. La clase Directorio podrá contener tanto archivos como otros directorios, es decir, contiene una serie de AbstractArchivo.

Código

La clase que podríamos decir principal que es la que tendrán que extender las clases que quieran ser tratadas.

public abstract class AbstractArchivo {    protected String name;    protected Indentacion indentacion;    public abstract void mostrar();}

Los archivos y los directorios son las clases que deberán extender de la clase abstracta.

public class Archivo extends AbstractArchivo {    public Archivo(String name, Indentacion indentacion) {            this.name = name;            this.indentacion = indentacion;    }    @Override    public void mostrar() {            System.out.println(indentacion.getIndentacion() +name);    }}public class Directorio extends AbstractArchivo {    private ArrayList<AbstractArchivo> files = new ArrayList<AbstractArchivo>();    public Directorio(String name, Indentacion indentacion) {        this.name = name;        this.indentacion = indentacion;    }    public void add(AbstractArchivo f) {        files.add(f);    }    @Override    public void mostrar() {        System.out.println(indentacion.getIndentacion() + name);        indentacion.aumentarIndentacion();        for (AbstractArchivo file : files) {            file.mostrar();        }        indentacion.decrementarIndentacion();    }}

Y la clase Indentacion una clase auxiliar que no interfiere esquema general del patrón.

public class Indentacion {    private StringBuffer sbIndent = new StringBuffer();    public String getIndentacion() {        return sbIndent.toString();    }    public void aumentarIndentacion() {        sbIndent.append(" ");    }    public void decrementarIndentacion() {        if (sbIndent.length() >= 3) {            sbIndent.setLength(sbIndent.length() - 3);        }    }}

A continuación podemos ver un ejemplo de como se instanciarían:

public class Cliente {    public static void main(String[] args) {        Indentacion indentation = new Indentacion();        Directorio dirOne = new Directorio("dir111", indentation);        Directorio dirTwo = new Directorio("dir222", indentation);        Directorio dirThree = new Directorio("dir333", indentation);        Archivo a = new Archivo("a", indentation);        Archivo b = new Archivo("b", indentation);        Archivo c = new Archivo("c", indentation);        Archivo d = new Archivo("d", indentation);        Archivo e = new Archivo("e", indentation);        dirOne.add(a);        dirOne.add(dirTwo);        dirOne.add(b);        dirTwo.add(c);        dirTwo.add(d);        dirTwo.add(dirThree);        dirThree.add(e);        dirOne.mostrar();    }}

El patrón Composite es especialmente útil combinado con otros patrones en especial con patrones de creación o otros patrones como el: Adapter o el Strategy.

Como siempre os dejo el código empleado.

Para ti
Queremos saber tu opinión. ¡Comenta!