sábado, mayo 13, 2006

beans inmutables

Usualmente, para modelar clases inmutables suele darse un conjunto de constructores públicos que toman de argumento el estado en el que debe quedar la instancia inmutable. Una desventaja que trae esta técnica es que no se lleva bien con otro consejo conocido: prefierase una lista de argumentos breve siempre que sea posible. Un ejemplo típico de una clase inmutable podría ser la siguiente:


/**
* Modela un punto en un espacio bidimensional
*
* Esta clase es inmutable
*/
final class Point {
private final int x,y;

public Point(int x,int y) {
this.x=x;
this.y=y;
}

public int getX() {
return x;
}

public int getY() {
return y;
}
}

El hecho de tener una lista compleja de argumentos trae varias desventajas:

  • El orden de los argumentos es artificial, por lo general no hay ninguna relación entre la posición de un argumento y lo que este representa. Por ejemplo, sería igualmente aceptable tomar como primer argumento un valor de una fila en una matríz y como segundo, un valor de una columna o viceversa.
  • El usuario debe conocer exactamente que representa cada argumento, aún cuando podría estar interesado solo en algunos de ellos.

  • Construir un nuevo objeto inmutable a partir de otro implica reconstruir el estado para poder pasarlo en la lista de argumentos (lo cual implica un conocimiento muy preciso del estado de la clase).

  • La extensión de la clase probablemente implique una modificación de los constructores, esto rompe el código cliente.

Una solución a este problema sería implementar algo parecido a un bean de java con la propiedad de inmutabilidad (un bean inmutable). Puede resultar interesante mirar String e Integer de la API de java ya que tienen este enfoque. Las condiciones que estos beans que debería cumplir son:

El objeto construido es inmutable
  • El objeto posee un constructor por defecto razonable
  • se puede obtener información sobre el objeto utilizando un conjunto de métodos getters
  • se puede obtener un nuevo objeto con alguna modificación en su estado respecto a otro objeto usando un conjunto de metodos setters

Un ejemplo de estos beans inmutables:

/**
* Modela un punto en un espacio bidimensional
*
* Esta clase es inmutable
*/
final class Point {
private final int x;
private final int y;

public static final Point Zero=new Point(0,0);

private Point(int x,int y) {
this.x=x;
this.y=y;
}

public int x() {
return x;
}

public int y() {
return y;
}

public Point x(int x) {
return new Point(x,this.y);
}

public Point y(int y) {
return new Point(this.x,y);
}
}

Basta revisar la lista de problemas presentados originalmente y comprobar que no se mantiene
ninguno de ellos.

claves: inmutable, beans, java beans, patterns

3 Comments:

Anonymous Anónimo said...

Los Builders resuelven ese problema que contás. Permiten partir el proceso de creación de un objeto en partes más simples, para finalmente generar el objeto en cuestión. Ahí tenés inmutabilidad y simplicidad en la creación.

3:11 p. m.  
Anonymous Anónimo said...

Para eso están los Builders. Te proveen inmutabilidad y simplicidad en la creación (ya que se hace por partes). La creación del objeto se prepara con anterioridad y se realiza luego atomicamente (en el build())

3:13 p. m.  
Blogger Hernan Rancati said...

Claro! Esa es otra manera de resolver los problemas mencionados e incluso algunos otros. Se podría pensar estos beans inmutables como la fusión entre un bean y un builder (tomándose alguna licencia:).

Por otro lado, tener un builder suele ser mas incómodo para el usuario (como pasa con el uso de muchos otros patterns). Por ejemplo: uno encuentra una interfaz que quiere usar pero la documentación indica que tiene que remitirse a algún builder, lo tiene que encontrar, puede haber mas de uno, etc. Además, le da bastante mas trabajo a el diseñador y el implementador: uno termina teniendo -como mínimo- lo siguiente: una clase, una interfaz y un builder. Algo que tampoco me convence mucho es que el builder y la clase se terminan repartiendo los metodos: ej. Los getters a la clase y los setters al builder.

Curiosamente, hace un tiempo estaba usando builders para cierta tarea y terminé quitando la mayoría en favor de este diseño porque me resultaban muy incómodos de mantener. De momento sigo muy contento con el cambio:)

> Pero te digo que los builders son
> mas potentes

tenés razón pero no los voy a volver a escribir por eso! ;)

Un abrazo, Her

5:14 p. m.  

Publicar un comentario

<< Home