Composite
Propósito:
Motivación:
A veces es necesario trabajar tanto con elementos simples como con colecciones, donde las colecciones son formadas por múltiples elementos simples o por otras colecciones. Un sencillo ejemplo de esto son las aplicaciones de dibujo, donde se tiene la posibilidad de crear elementos de dibujo simples (líneas, rectángulos, textos, etc.) y luego agrupar con el objetivo de operar con todo el conjunto, o composición, como si fuera una unidad. A su vez, las composiciones se pueden volver a agrupar con más elementos simples o con tras composiciones, de la misma manera las aplicaciones gráficas tienen componentes que pueden agruparse para formar componentes mayores (contenedores). De esta forma se obtienen estructuras de árbol con las cuales se puede operar.
Aplicabilidad:
Para representar jerarquías de objetos parte-todo, para que los clientes puedan manejar indistintamente objetos individuales o composiciones de objetos tratándolos en la estructura composite de manera uniforme. Como los componentes pueden almacenar múltiples padres, puede resultar una ambigüedad al recorrer la estructura hacia arriba. Dependiendo de la aplicación puede ser necesario o no el ordenamiento de los hijos, cuando el ordenamiento es importante, uno debe diseñar cuidadosamente una interfaz para el manejo y el acceso de los hijos. El patrón Iterator puede ser de utilidad para este objetivo. Si es necesario recorrer o buscar en las composiciones con frecuencia, la clase Composite puede almacenar en un cache cierta información sobre esta tarea.
Estructura:
Participantes:
Los clientes usan la interfaz Component para acceder a los objetos dentro de la composición. Si se trabaja contra un objeto simple, la petición se maneja directamente. Si se trabaja contra un objeto de composición, entonces, por lo general, la petición es dirigida a todos los hijos, en algunos casos, realizando algunas tareas previas y posteriores a la operación.
Consecuencias:
Usos Conocidos:
Component:
- Declara la interfaz que presentarán los objetos en la composición.
- Implementa el comportamiento predeterminado para todas las clases, según corresponda.
- Declara una interfaz para acceder y administrar sus componentes hijos.
Leaf:
- Representa los objetos simples. No poseen hijos.
- Define el comportamiento explícito de cada objeto simple.
Composite:
- Define el comportamiento de los objetos que tienen hijos.
- Almacena los objetos hijos.
- Implementa las operaciones referentes a los hijos.
Client:
- Maneja los objetos en la composición mediante la interfaz Component.
Colaboraciones:
- Define jerarquías de clases que tienen objetos primitivos y objetos compuestos (composite)
- La composición puede ser recursiva.
- Hace el cliente simple.
- Puede tratar la estructura y los objetos individuales uniformemente.
- Facilita la adición de nuevas clases de componentes.
- Puede hacer que el diseño sea demasiado general.
- Hace más difícil restringir los componentes de un composite– Si se quiere hacer que un composite sólo tenga ciertos componentes hay que codificar las comprobaciones para que se realicen en tiempo de ejecución.
Implementación:
El siguiente ejemplo muestra su funcionalidad, puesto que se permite crear compuesto de moléculas, conde cada molécula con mínimo un átomo de oxigeno posee o adiere más moleculas de hidrógeno, creando niveles en su diseño.
package Logica;
/**
*
* @author Paola
*/
public abstract class Componente {
protected String nombre;
protected String hojaInfor;
protected String informacion;
protected String informacion2;
public Componente(String nombre) {
this.nombre = nombre;
}
abstract public void agregar(Componente c);
abstract public void remover(Componente c);
abstract public void mostrar(int prof);
abstract public String getInformacion1();
abstract public String getInformacion2();
}
package Logica;
import java.util.ArrayList;
/**
*
* @author Paola
*/
public class Compuesto extends Componente {
private ArrayList hijo = new ArrayList();
public Compuesto(String name) {
super(name);
}
public int getSize() {
return hijo.size();
}
@Override
public void agregar(Componente componente) {
hijo.add(componente);
}
@Override
public void remover(Componente componente) {
hijo.remove(componente);
}
@Override
public void mostrar(int prof) {
informacion2 = this.getInformacion1() + "\n";
for (int i = 0; i <>
hijo.get(i).mostrar(prof + 1);
informacion2 = informacion2 + hijo.get(i).getInformacion2() + "\n";
}
}
@Override
public String getInformacion2() {
return informacion2;
}
@Override
public String getInformacion1() {
return nombre;
}
}
package Logica;
/**
*
* @author Paola
*/
public class Hoja extends Componente {
public Hoja(String nombre) {
super(nombre);
}
public String getInformacion2() {
return hojaInfor;
}
public void agregar(Componente c) {
System.out.println("Se ha adicionado un componente");
}
public void remover(Componente c) {
System.out.println("Se ha removido el componente");
}
public void mostrar(int prof) {
hojaInfor = " - " + nombre;
}
@Override
public String getInformacion1() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
package Logica;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
/**
*
* @author Paola
*/
public class Laboratorio extends JFrame implements ActionListener {
private JTextArea tablero;
private String texto;
private JButton hidrogeno;
private JButton oxigeno;
private JButton combinarMoleculas;
private JButton nuevoCompuesto;
private JLabel contOxigeno;
private JLabel contHidrogeno;
private String nombre;
private int numHidrogenos = 0;
private int hidrogenosNivel = 0;
private Compuesto temp;
private Compuesto raiz;
private int contador = 0;
private int combinacion = 0;
private boolean inicio = false;
private int i;
private int numOxigeno = 0;
private boolean mostrar = false;
public Laboratorio() {
this.setLayout(null);
this.setTitle("Laboratorio de Moléculas");
this.setSize(400, 500);
this.setLocation(100, 100);
tablero = new JTextArea();
tablero.setSize(350, 300);
tablero.setLocation(10, 10);
tablero.setText("");
tablero.setEditable(false);
add(tablero);
JScrollPane areaScrollPane = new JScrollPane(tablero);
areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
areaScrollPane.setSize(350, 300);
areaScrollPane.setLocation(10, 10);
this.getContentPane().add(areaScrollPane);
oxigeno = new JButton();
oxigeno.setSize(100, 20);
oxigeno.setLocation(20, 400);
oxigeno.setText("Oxigeno");
oxigeno.addActionListener(this);
add(oxigeno);
contOxigeno = new JLabel();
contOxigeno.setSize(20, 10);
contOxigeno.setLocation(60, 380);
contOxigeno.setText("");
contOxigeno.setVisible(true);
add(contOxigeno);
hidrogeno = new JButton();
hidrogeno.setSize(100, 20);
hidrogeno.setLocation(140, 400);
hidrogeno.setText("Hidrogeno");
hidrogeno.addActionListener(this);
add(hidrogeno);
contHidrogeno = new JLabel();
contHidrogeno.setSize(20, 10);
contHidrogeno.setLocation(180, 380);
contHidrogeno.setText("");
contHidrogeno.setVisible(true);
add(contHidrogeno);
combinarMoleculas = new JButton();
combinarMoleculas.setSize(100, 20);
combinarMoleculas.setLocation(260, 400);
combinarMoleculas.setText("Combinar");
combinarMoleculas.addActionListener(this);
add(combinarMoleculas);
nuevoCompuesto = new JButton();
nuevoCompuesto.setSize(150, 20);
nuevoCompuesto.setLocation(110, 350);
nuevoCompuesto.setText("Nuevo Compuesto");
nuevoCompuesto.addActionListener(this);
add(nuevoCompuesto);
addWindowListener(new Cierre());
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == oxigeno) {
if (combinacion == 0 && inicio == false) {
JOptionPane.showMessageDialog(null, "Primero debe crear un objeto compuesto");
}
if (combinacion == 0 && inicio == true) {
contador++;
numOxigeno++;
nombre = nombre + contador;
raiz = new Compuesto(nombre);
inicio = false;
}
if (combinacion == 1 && inicio == false) {
contador++;
nombre = nombre + contador;
temp = new Compuesto(nombre);
numOxigeno++;
}
}
if (e.getSource() == hidrogeno) {
if (contador != 0 && numOxigeno != 0) {
++hidrogenosNivel;
++numHidrogenos;
contHidrogeno.setText("" + hidrogenosNivel);
if (combinacion == 0) {
nombre = "Hidrogeno " + numHidrogenos;
raiz.agregar(new Hoja(nombre));
mostrar = true;
} else {
nombre = "Hidrogeno " + hidrogenosNivel;
temp.agregar(new Hoja(nombre));
mostrar = true;
}
} else {
JOptionPane.showMessageDialog(null, "El compuesto debe tener almenos un átomo de oxígeno");
}
}
if (e.getSource() == nuevoCompuesto) {
contHidrogeno.setText("");
hidrogenosNivel = 0;
mostrar = false;
nombre = JOptionPane.showInputDialog("Nombre para la molécula");
nombre = "Oxigeno " + nombre + " nivel: ";
if (contador == 0) {
inicio = true;
} else {
combinacion = 1;
numOxigeno = 0;
}
}
if (e.getSource() == combinarMoleculas) {
if (combinacion == 1) {
mostrar = true;
contHidrogeno.setText("");
raiz.agregar(temp);
temp = null;
combinacion = 0;
} else {
JOptionPane.showMessageDialog(null, "Debe terner un compuesto creado para adicionarlo.");
}
}
if (contador != 0 && mostrar == true) {
texto = "";
for (i = 0; i <>
raiz.mostrar(i);
tablero.setText(raiz.getInformacion2() + "\n");
}
}
}
}
class Cierre extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
package interfaz;
import Logica.*;
/**
*
* @author Paola
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Laboratorio lab=new Laboratorio();
lab.setVisible(true);
}
}
Ejemplos de los compuestos modelo se puede encontrar en casi todos orientados a objetos sistemas. El original de la clase Ver Smalltalk Modelo / Vista / Controlador [KP88] es un compuesto, y casi todas las herramientas de interfaz de usuario o marco ha seguido en sus pasos, incluyendo ET ++ (con sus VObjects [WGM88]) y entrevistas (Estilos [ICL 92], Gráficos [VL88], y, glifos [CL90]). Es interesante observar que la Ver original de Modelo / Vista / Controlador había un conjunto de subviews; en otras palabras, Ver es a la vez el componente de clase y la clase de compuestos. Liberación de 4,0 Smalltalk-80 Modelo / Vista / Controlador VisualComponent con una clase que ha
Ver CompositeView y subclases.
Patrones Relacionados:
- Chain of Responsibility: Usualmente usado en el vínculo componente-padre.
- Decorator: Cuando son usados en conjunto, tendrán una clase padre en común. Por lo tanto Decorator tendrá que soportar la interfaz de un componente (Add, Remove y GetChild).
- Flyweight: permite compartir componentes, pero ya no pueden tener una referencia al padre.
- Iterator: puede ser usado para recorrer las composiciones.
- Visitor: localiza operaciones y comportamiento que, de otra manera, serian distribuidos a través de las clases Composite y Leaf.
Referencias:
- PDF-Departamento de Sistemas Informáticos y Programación Curso de doctorado 1999 -2000 Patrones de diseño orientado a objetos.
- DesIgn Patterns: Elements of Reusable Object-Oriented Software Gamma, Helm, Johnson, Vlissides Editorial Addison-Wesley.
- Diseño y Programación Orientado a Objetos. Capítulo 4. Ingeniería Informática Ingeniería Técnica de Informática de Sistemas y Gestión Optativa. http://www.info-ab.uclm.es/asignaturas/42579
No hay comentarios:
Publicar un comentario