viernes, mayo 21, 2010

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

Ahora 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:
  1. ¡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)
  2. 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.
  3. 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.

Bueno, espero haber limpiado alguna duda, y abrir otras ;) Saludos.

jueves, mayo 13, 2010

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.
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 toda la 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.getPerfil(...);

El new de creación esta dentro del metodo agregarPerfil. 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!!!

miércoles, mayo 12, 2010

SCJP 1.6 de Java


Hace unas semanas a tras he decidido rendir la certificación SCJP 1.6 de Java. La verdad es que en un principio, me resultaba medio confusa y bastante difícil. Pero después a medida que estudiaba el libro, y lo traducía de apoco, por que la única versión que existe es en ingles, y además el examen es en inglés, fui adquiriendo un mayor ritmo para la resolución de los ejercicios. Creo haber aprendido un montón de cosas que desconocía a cerca del lenguaje. Esta muy buena y es super aconcejable, así qué, cuando tengan un tiempo (notece que dije tiempo y no tiempito) se pueden encomendar a esta campaña. Existe info de sobra en la web de como rendirla, o sea vasta googlear "SCJP 1.6 de Java" para toparce con foros, blogs y paginas que contienen PDFs con manuales, algununos simuladores, jugos etc. Lo que no se encuentra a simple vista es tips y estrategia para afrontar el examen.
En mi caso personal, y al conversar con algunos amigos que ya la habían rendido, me dí cuenta que la clave principal, es el TIEMPO, repito en mi caso personal, ya qué no sé si todas las versiones del examen serán iguales, pero contaba con 60 preguntas, y un tiempo máximo de resolución de 3hs. Que si contamos con los deditos nos da un total de 3 minutos por pregunta. Bien, existen preguntas que exeden por lejos ese tiempo, ya que tienen codigo largo, confuso y si además le sumamos que hay demaciadas preguntas tramoposas en el examen, por lo que por más que seamos "don java" si nos dormimos por un segundo, se nos va a pasar algun import o punto y como o algo así. Yo no sabía cual sería la duración, ni cuantas preguntas tendría, por que cada pagina daba una duracion diferente, por lo que decidí entrenarme con un timpo de resulución de 4 minutos por pregunta, con las preguntas del libro, y ni ahun así lograba resolverlas a todas. Llegado el dia, y al darme cuenta que solo tenia 3 minutos, decidí, no escarbar tanto en las preguntas, y si tenian "trampa" que así sea. La hipotesis fué que serían las menos. Y para ser mi primer intento, logré certificar. Es más me quedo unos 15 minutos para hacer una rápiada repasada del examen donde logre reveer un 30% de las preguntas y salvar 2.
Algunos datos utiles en argentina:

- Tiempo de duración: 3hs (180 min)
- Total de Preguntas: 60
- Score para aprobar: 58% (35 Preguntas)
- Ojo con las preguntas de arrastrar y soltar se pueden resetear
- Codigo del examen: 310-065
- Libro (PDF): Sun Certified Programmer for Java 6 - Study Guide
- Libro en Papel: Sun Certified Programmer for Java 6 - Practice Exams (No se molesten en buscarlo en PDF, solo sale la versión en papel, Y NO LO TENGO, por lo que si alguien lo tiene en PDF me lo podría habilitar.
- Simuladores: Wizlabs, Sybex, intrepid
- 1 Blog: http://scjp-sun.blogspot.com/
- Juegos para practicar: http://faq.javaranch.com/java/ScjpMockTests
- info sobre la certificacion: http://osum.sun.com/
- Donde inscribirse para rendir: www.prometric.com



Lic Ariel Diaz Molina
Java Certified Programmer