Thursday, September 6, 2012

Siguiendo el estilo Java Beans


En el post anterior ( http://ferrocastro.blogspot.mx/2012/09/como-crear-objetos.html) nos referimos al uso de métodos estáticos de fábrica para complementar la creación de objetos por esa vía, en lugar de usar los constructores de la clase. Veamos ahora otros problemas que surgen con la creación de objetos con constructores y cómo pueden solucionarse.
Supongamos que en un sistema de control escolar, modelamos el concepto estudiante con la clase siguiente:
public class Estudiante {
  private final  int id; // El número de matrícula del estudiante
  private final String nombre; // Sus nombres y apellidos
  private final Calendar fechaDeNacimiento;
  private String carrera; // la carrera que cursa
  private int semestre; //el semestre que cursa
  private String imss; // El número de seguridad social del IMSS
  private String issste; // el número del seguro social del ISSSTE
  private boolean gimnasio;// el estudiante hace uso o no del gimnasio
  boolean becario; // el estudiante realiza actividades de becario
  // Constructores para la clase Estudiante
  // Vienen aquí los constructores de la clase
  // Comportamiento asociado al estudiante
  //Vienen aquí los métodos
}
Se nos pueden ocurrir otros atributos, o que algunos de los atributos que hemos añadido pueden encapsularse en otras clases, pero el objetivo no es discutir sobre el buen diseño de los atributos. Lo que queremos destacar, es que de ese conjunto de atributos, algunos será siempre requeridos y otros serán opcionales, y que esa consideración debe tomarse en cuenta para el diseño de los constructores de la clase.
Supongamos (pienso que es una buena suposición) que los valores de los atributos id, nombre, fechaDeNacimiento, carrera y semestre siempre se requieren para crear un objeto de clase Estudiante y que el resto de los atributos pueden tomar valores opcionales. Noten que también he establecido que los atributos id, nombre y fechaDeNacimiento son constantes, por lo que estaremos obligados a inicialziarlos, bien en el momento de su declaración (que no hemos hecho) o en sus constructores que tenemos que hacer.
Es costumbre en un caso como éste, escribir varios constructores para aprovechar esos valores opcionales para algunos de los atributos y no tener que pasarlos como argumentos en el caso que esos valores sean los que se desean para el objeto creado.
Procedemos entonces a armar un telescopio "plegable" y escribimos los siguientes constructores para esa clase:
public class Estudiante {
  //Atributos requeridos
  private final  int id; // El número de matrícula del estudiante
  private final String nombre; // Sus nombres y apellidos
  private final Calendar fechaDeNacimiento;
  private String carrera; // la carrera que cursa
  private int semestre; //el semestre que cursa
  //Atributos opcionales
  private String imss =null; // El número de seguridad social del IMSS
  private  String issste=null; // el número del seguro social del ISSSTE
  private boolean gimnasio=false;// el estudiante hace uso o no del gimnasio
  boolean becario=false; // el estudiante realiza actividades de becario
  // Constructores para la clase Estudiante
  public Estudiante( int id, String nombre, Calendar fechadeNacimiento, String carrera, int semestre) {
     this (id, nombre, fechaDeNacimiento, carrera, semestre, null);
  }
 public Estudiante(int id,String nombre, Calendar fechaDeNacimiento, String carrera, int semestre, String imss) {
    this (id, nombre, fechaDeNacimiento, carrera, semestre, imss, null);
  }
  public Estudiante(int id,String nombre, Calendar fechaDeNacimiento, String carrera, int semestre, String imss,String issste) {
    this (id, nombre, fechaDeNacimiento, carrera, semestre, imss, issste, false);
  }
  public Estudiante(int id,String nombre, Calendar fechaDeNacimiento, String carrera, int semestre, String imss,String issste, boolean gimnasio) {
     this (id, nombre, fechaDeNacimiento, carrera, semestre, imss, issste, gimnasio, false);
  }
  public Estudiante( int id, String nombre, Calendar fechadeNacimiento, String carrera, int semestre, String imss,String issste, boolean gimnasio,  boolean becario) {
    this.id = id;
    this.nombre =nombre;
    this.fechaDeNacimiento = fechaDeNacimiento;
    this.carrera = carrera;
    this.semestre =semestre;
    this.imss =imss;
    this.issste = issste;
    this.gimnasio = gimnasio;
    this.becario = becario;
  }

  // Comportamiento asociado al estudiante
  //Vienen aquí los métodos
}
Llegamos entonces a lo que Joshua Bloh le llama el "telescoping ocnstructor", en ausencia de la técnica de parámetros con nombres. Podrían haberse escrito más constructores para considerar todas las posibles combinaciones de los parámetros opcionales, en lugar de tener que especificar valores opcionales en las llamadas a los constructores, pero con los que ya hemos escrito basta para indicar que seguramente habrán otras soluciones "más elegantes".
Salta a la vista, sobre todo para aquellos que ya conocen la técnica de contenedores que administran objetos y que usan inyección de dependencias, que una solución sería escribir setters para los atributos al estilo de Java Beans. El código siguiente realiza eso aunque no escribimos todos los setters:
public class Estudiante {
  private  int id; // El número de matrícula del estudiante
  private String nombre; // Sus nombres y apellidos
  private Calendar fechaDeNacimiento;
  private String carrera; // la carrera que cursa
  private int semestre; //el semestre que cursa
  private String imss =null;; // El número de seguridad social del IMSS
  private String issste =null; // el número del seguro social del ISSSTE
  private boolean gimnasio = false;// el estudiante hace uso o no del gimnasio
  boolean becario= false; // el estudiante realiza actividades de becario
// Constructor sin argumentos para seguir la convención Java Beans
  public Estudiante () {
  }
//Setters:
  public void setId (int id) { this.id =id;}
  public void setNombre(String nombre) {this.nombre =nombre;}
  public void setFechaDeNacimiento( Calendar fechaDeNacimiento) { this.fechaDeNacimiento = fechaDeNacimiento,}
  public void setCarrera (String carrera) {this.carrera =carrera;}
  public void setSemestre (String semestre) {this.semestre = semestre};
  public setImss(String imss) {this.imss = imss;}
  public setIssste(String issste) {this.issste = issste;}
  public setGimnasio( boolean gimnasio) = {this.gimnasio = gimnasio;}
  public setBecario (boolean becario) {this.becario = becario;}
  // Y así con los setters para el resto de los atributos
  // Comportamiento asociado al estudiante
  //Vienen aquí los métodos
}
Con el diseño anterior, creamos un estudiante de la siguiente forma:
Estudiante geek = new Estudiante();
geek.setId(14327);
geek.setNombre("Juan de los Palotes");
geek.setFechaDeNacimento(Calendar.set(1990,12,31);
geek.carrera("Brujeria avanzada");
geek.semestre(9);
geek.becario(true);
Dos problemas se presentan al seguir la convención de Java Beans: no podemos lograr atributos inmutables (noten que suprimí el final) y el proceso de obtener un objeto de tipo Estudiante "consistente" ocupa más de una sentencia, por lo que entre sentencias tenemos un objeto inconsistente. Cuando trabajamos con un modelo de componentes orientado a contenedores, el contenedor no me "entrega" el objeto hasta que lo tenga totalmente consistente y el grado de consistencia lo establecemos nosotros.
¿Habrá(n) otra(s solución(es)?
Por supuesto, pero la dejamos para el siguiente post.

No comments: