lunes, 25 de mayo de 2009

Hacia un Framework de Persistencia: Capítulo 3 – Patrón Singleton

Planteemos primeramente una situación en dónde DESCONOCEMOS la existencia de los patrones de diseño, en particular del Patrón Singleton.


public class Alumno {

private static int codigoGlobal = 0; //Atributo de clase

private int codigoAlumno; //Atributo de c/instancia de clase (cada objeto)

private String nombre; //Atributo de c/instancia de clase (cada objeto)


public Alumno(String nombre){ //Constructor por parámetros

this.nombre = nombre;

this.codigoAlumno = ++codigoGlobal; // PRIMERO se hace el incremento de codigoGlobal y luego se asigna a codigoAlumno

}

}


¡Al fin algo de código!

No hay mucho por agregar, una clase Alumno que, cómo caso particular, para generar su código se vale de una variable de clase "códigoGlobal" la cual será incrementada en cada instancia que se genere de la clase Alumno. Cada instancia almacenará su códigoAlumno.

¿Qué problemas trae este procedimiento? Estamos involucrando en la clase Alumno algo que deberían poder consultar SIN la posibilidad de modificar, además la clase Alumno no tendría por qué hacerse cargo del códigoGlobal.

Si lográramos llevar este comportamiento a una clase diferente podríamos tener un único punto de acceso. Es decir, cada cosa que quisiera modificar lo hago en esta nueva "clase", sin tocar la clase Alumno. Luego es intuitivo, podríamos tener un GestorDeAlumnos (una clase que se encargaría de instanciar nuevos Alumnos, dar de bajo a Alumnos, etc) para consultar ésta nueva "clase" que ahora llamaremos "SingletonAlumno" para hallar el códigoGlobal que antes estaba en la clase Alumno. Veamos en código cómo quedaría.


public class Alumno2 {

private int codigoAlumno;

private String nombre;


public Alumno2(String nombre){

this.nombre = nombre;

}


public void setCodigoAlumno(int codigoAlumno){

this.codigoAlumno = codigoAlumno;

}

}


public class SingletonAlumno {

private static SingletonAlumno singleton;

private int codigoGlobal;


private SingletonAlumno(){

codigoGlobal = 0;

}


public static SingletonAlumno getSingleton(){

if (singleton == null) singleton = new SingletonAlumno();

return singleton;

}


public int getCodigo(){

return ++codigoGlobal;

}

}


public class GestorAlumno {

private ArrayList list;


public void addAlumno(Alumno2 a){

int codigoAlumno = SingletonAlumno.getSingleton().getCodigo();

a.setCodigoAlumno(codigoAlumno);


list.add(a);

}

}

Ya sé, seguro dijeron, ¿pero está loco?, ¿más clases, más CÓDIGO?, ¿en qué demonios gané?

Pasemos a analizar brevemente lo que realiza el código. Lo más importante de aquí es la clase SingletonAlumno. Con esta definición estamos garantizando que será un único punto de acceso en el programa. Al declarar una variable de clase y privada "singleton" estamos asegurando que desde afuera sólo se podrá acceder con el método público getSingleton(). Piensen un ratito… ¿me pueden generar una instancia de la clase SingletonAlumno?... NO, el único constructor es privado. Listo, problema resuelto. Repito. ÚNICO punto de acceso del programa. Lo demás es comprensible.

¡Ah! Se me olvidaba, combiné algo de "filosofía objetos". Desde el programa con el cuál interactúe el usuario, nunca podrá recibirse un código de alumno por parte del mismo. Al menos en nuestro caso es así, porque por política optamos que sea "autogenerado" el códigoAlumno. Esto se puede ver claramente en el manejo del gestor. El Alumno que me pasan sólo tendrá nombre y el gestor se encargará de establecer su código (previo pedido al ÚNICO encargado de manejar el códigoGlobal de los alumnos, o sea, el SingletonAlumno).

Talvez se nos hizo un poco tedioso, no importa, lo importante de todo esto es esclarecer el uso de patrones. Retomemos la pregunta, ¿en qué gané con esto? Bien, sólo aprendimos, no ganamos más que eso. Pero, ¡no es poco! Absolutamente ¡NO es poco! No se puede ver, como dije, en esta sencilla situación la bondad del patrón singleton, pero la experiencia mostrará lo suyo.

Ahora sí estamos en condiciones, un poco más formal, junto a mí buen libro de Erich Gamma, de plantear el patrón Singleton resumidamente en dos o tres palabras:

Propósito del patrón Singleton: Garantizar que una clase sólo tenga una instancia, y proporcionar un punto de acceso global a ella.

Cuándo utilizarlo:

  • Cuando deba haber sólo una instancia de una clase y ésta ser accesible por los clientes.
  • La única instancia debería ser extensible mediante herencia y los clientes deberían poder usar ésta sin modificar su código.

Beneficios:

  • Acceso controlado a una única instancia.
  • Espacio de nombres reducidos.
  • Permite refinamiento de operaciones.
  • Más flexible que las operaciones de clase.

Listo, lo demás escapa del objetivo de este capítulo. En la próxima nos metemos con el patrón Facade, el cual usaremos en nuestro FWP.

¡Hasta luego!


No hay comentarios: