Diagramas de clases. Relaciones

Posted on Actualizado enn

UML, Agregacion y Composicion
He visto demasiadas discusiones vicentinas sobre las diferencias entre la agregación y la composición en los diagramas de clases de UML. Es más, cada cierto tiempo, alguien surge y me pregunta cual es la diferencia en el código y me explica sus propias teorías sobre esta cuestión, este debate es casi tan extenso como el de los extends y los includes de los casos de uso.

UML: Diferencia Agregacion, Asociacion y Composición. Codigo
Empecemos, debemos recordar siempre que una de las mayores criticas que recibe UML, es que ha logrado salvar muchas ambigüedades… Pero no todas!!! aun quedan conceptos que se prestan a dobles interpretaciones, no se si este será uno de ellos, pero por lo discutido parece que sí. Por otro lado, podemos hacer un poco de historia, recordando que primero existió la asociación, después surge la Agregación para representar un relacion estructural contenedor/contenido y luego como una “extensión” de esta ultima nace la Composición.
Para explicar mi punto de vista voy a echar mano, al diagrama de clases que ya he utilizado en otro post y después voy a poner el código de la clase Persona, que es la que se lleva todala carga de la discusiónEl código hace referencia, solo a este modelo, y es bien detallado, hasta con cosas innecesarias, o meramente teóricas, pero lo que busco es fijar una posición, concreta y definitiva, en el tema de las relaciones.

Algo importante a tener en cuenta, es que un objeto existe (digamos que esta vivo, pero esto no es técnicamente correcto por que no es un hilo) mientras existe una variable de referencia que “apunte” (tampoco correcto, por que java no tiene punteros, je) a dicho objeto en memoria. Es decir que se convertirá en elegible para ser borrado por el garbage collector, cuando no exista una variable que “apunte” a dicho objeto.


import java.util.LinkedList;
import java.util.List;

public class Persona {
private String nombre;
private String apellido;
private List perfiles = new LinkedList();
private List lugaresFrecuentes = new LinkedList();

//Setters and Getters
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}

// OJO no confundir estos son solo setters y getters de las propiedades
public List getPerfiles() {return perfiles;}
public void setPerfiles(List perfiles) {this.perfiles = perfiles;}
public List getLugaresFrecuentes() {return lugaresFrecuentes;}
public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}

La clase comienza normalmente con la declaración de las variables de instancia. Donde perfiles y lugaresFrecuentes

son dos colecciones, pero tranquilamente podrían ser arrays. que se transformarán en contenedores de elementos. Al ser propiedades tienen getters y setters (accessors y mutators), que nada tienen que ver con la agregación y la composición.
Ahora veamos cuales son los métodos que caracterizan a la relación de AGREGACIÓN


public void agregarLugarFrecuenta(Lugar lugar){
if(!lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.add(lugar);
}
}
public void removerLugarFrecuenta(Lugar lugar){
if(lugaresFrecuentes.contains(lugar)){
lugaresFrecuentes.remove(lugar);
}
}

La primera característica es que la clase contiene dos métodos uno que agrega elementos a la coleccion y otro que los elimina de ella. He acá algo importante… los objetos son pasados por parametro, no han sido instanciados dentro del método, es decir no hemos realizado el new del objeto. Ha “nacido” en cualquier otra parte y se lo hemos pasado por parámetro al método para ser agregado a la lista lugaresFrecuentes. En otras palabras, el objeto Persona podria morir, y el objeto ahun podría mantener una referencia activa en alguna otra parte de nuestro codigo por lo tanto sus ciclos de vida no estrían atados. No nace ni muere, dentro de la Persona.

¿Cual es la Diferencia con la COMPOSICIÓN?


public void agregarPerfil(){
Perfil p = new Perfil();
perfiles.add(p);
}
//sobrecarga
public void agregarPerfil(String nombre){
Perfil p = new Perfil(nombre);
perfiles.add(p);
}
public void removerPerfil(int index){

perfiles.remove(index); // aca lo quitamos de la lista

}
Bueno… la composición también tiene los métodos para agregar y borrar. Pero…

“el new del objeto se realiza dentro del método agregar”

la instanciación del objeto p se realiza dentro del método agregar y la referencia no se devuelve (es void o boolean), la variable de referencia local va a dejar de existir una vez que el método se termine de ejecutar, y el ciclo de vida de esa instancia en particular va a quedar atada a la lista, y por ende a la Persona. Una vez que el objeto Persona no se referencie más, (o sea muera, aunque técnicamente esto no es así) el objeto lista, quedará sin referencia, y por lo tantos sus elementos también. Además como el método no es estático, se deberá crear primero una instancia de Persona, para después poder agregar un Perfil. Empezando así a “atar” el ciclo de vida de un Perfil, al de una Persona.
En cuanto al método remover, no existe nada de extraordinario, simplemente quitamos un elemento de la lista.

Volviéndonos Paranoicos de la Teoría

Profundizando la paranoia y jugando con la teoría; para que atemos definitivamente los ciclos de vida, la variable lugaresFrecuentes no debería ser una propiedad, y la clase Perfil debería ser una Inner Class.
En el caso de la Inner class, hacemos esto para que se tenga que utilizar una instancia de la clase “Outer” para luego obtener una instancia de la clase Inner. Por ejemplo si en nuestro codigo, la clase Perfil, fuera una Inner class de la clase publica Persona (Se entiende no?, es decir que esta dentro del archivo Persona.java), para obtener una instancia de Perfil fuera de la clase persona tendríamos que hacer:
Persona persona = new Persona();
Persona.Perfil perfil = persona.new Perfil();

Y la clase Perfil existiría mientras exista la instancia de persona. (ciclos de vida atados)
En el caso de que la variable de instancia lugaresFrecuentes no debería tener getters y setters públicos, esto se debe a que ningún otra clase, con excepción de la clase Persona, debería tener la oportunidad de mantener una referencia viva a un objeto del contenedor. Y mucho menos obtener toda la Lista desde afuera! Un objeto Perfil, vive y muere con la Persona!
También de esto se pueden desprender otros delirios, como cuestiones de herencia y cosas así.
Pero de nuevo, y no me voy a cansar de decirlo… esto es un extremo!!, es solo para conversar entre amigos, o vanagloriarse con algún profesor, no tiene nada de practico, ni de real, salvo para casos específicos.

Paranoia de la Paranoia

¿Creían que ya habíamos terminado? aun se puede ser más paranoico!!!! mucho se ha discutido sobre estos temas, y mucho fue paranoia teórica. Lo siguiente, es algo que les llevará a sus amigos o profesor a decir, “…bueno pero eso ya es una locura”:
Sobreescribiremos el método finalize() de la Clase Persona, que es un método que todas las clases heredan de Object, y que se invoca justo antes de que un objeto sea borrado de la memoria por el garbage collector de java.

public void finalize(){
for(Perfil p : perfiles){
p = null;
}
}

En el desreferenciamos cada uno de los elementos de la lista un segundo antes de que el objeto de tipo Persona desaparezca de la memoria, una milésima de segundo, o algo asi!!! atando definitivamente el nacimiento y muerte, el ciclo de vida, de un elemento contenido con su contenedor.
Pero de nuevo!!! LA PARANOIA EN EL CÓDIGO NO ES BUENA!!! solo sirve en aquellas noches de borrachera entre programadores, en las cuales el boliche cerró y pinta quedarse en casa con amigos.

Yo rescataría de todo este biri-biri aquello de “el new se realiza dentro del método” y nada más!!!

UML, Asociacion y Agregacion
El post de la Agregación y Composición despertó otra pregunta más (Como siempre suele suceder, ya dije que el debate siempre dá para algo más). La duda viene por el lado de la diferencia entre asociación y Agregación en código. Se sostiene que es algo conceptual, que no se representa en código. Mi respuesta es que esto es 50% correcto. Ya que, como mencione antes (la etiqueta Diseño tiene mas sobre esto), la Asociación surgió primero, y la Agregación vendría a ser un tipo particular de Asociación. Ergo …Agregacion “IS-A” Asociación ¡punto para ud! . Primero veamos el diagrama UML

composicionAhora veamos el codigo de la clase Persona (Nota: imagínense los generics por que blogspot los toma como tags, así que no aparecen)

import java.util.List;

public class Persona {

private String nombre;
private String apellido;

private Foto foto;
private List lugaresFrecuentes;
private List comunicaciones;

public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellido() {return apellido;}
public void setApellido(String apellido) {this.apellido = apellido;}

//Asociacion Foto
public Foto getFoto() {return foto;}
public void setFoto(Foto foto) {this.foto = foto;}

//public List getLugaresFrecuentes() {return lugaresFrecuentes;}
//public void setLugaresFrecuentes(List lugaresFrecuentes) {this.lugaresFrecuentes = lugaresFrecuentes;}

//Agregacion
public void agregarLugar(Lugar lugar){
lugaresFrecuentes.add(lugar);
}
public boolean quitarLugar(Lugar lugar){
return lugaresFrecuentes.remove(lugar);
}
//Asociación
public void setComunicaciones(List comunicaciones) {
this.comunicaciones = comunicaciones;
}
public List getComunicaciones() {
return comunicaciones;
}

}

Las diferencias principales son que:
¡La Agregación son siempre colecciones, o arrays! O algo que sirva de contenedor para “agregar” más de un objeto, aunque agreguemos uno solo. (si no sería settear y no agregar, add)La Agregación cuenta con dos métodos: uno para “agregar” un solo objeto a la lista, y el otro para quitarlo de la misma.La agregación puede, como no, tener los metodos setter y getter, mientras que la Asociación siempre los tiene, que ponen y obtienen una variable de referencia del mismo tipo de la variable de instancia o de clase, en este caso List.

 

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s