Mi granito de java: Observer

Google+ Badge

sábado, 11 de junio de 2011

Observer

Este patrón de diseño permite reaccionar a ciertas clases llamadas observadores sobre un evento determinado.
Es usado en programación para monitorear el estado de un objeto en un programa. Está relacionado con el principio de invocación implícita. La motivación principal de este patrón es su utilización como un sistema de detección de eventos en tiempo de ejecución. Es una característica muy interesante en términos del desarrollo de aplicaciones en tiempo real.

Debe ser utilizado cuando:
  • Un objeto necesita notificar a otros objetos cuando cambia su estado. La idea es encapsular estos aspectos en objetos diferentes permite variarlos y reutilizarlos independientemente.
  • Cuando existe una relación de dependencia de uno a muchos que puede requerir que un objeto notifique a múltiples objetos que dependen de él cuando cambia su estado.

Este patrón tiene un uso muy concreto: varios objetos necesitan ser notificados de un evento y cada uno de ellos deciden como reaccionar cuando esta evento se produzca.
Un caso típico es la Bolsa de Comercio, donde se trabaja con las acciones de las empresas. Imaginemos que muchas empresas estan monitoreando las acciones una empresa X. Posiblemente si estas acciones bajan, algunas personas esten interesadas en vender acciones, otras en comprar, otras quizas no hagan nada y la empresa X quizas tome alguna decisión por su cuenta. Todos reaccionan distinto ante el mismo evento. Esta es la idea de este patrón y son estos casos donde debe ser utilizado.

Diagrama UML


Subject: conoce a sus observadores y ofrece la posibilidad de añadir y eliminar observadores. Posee un método llamado attach() y otro detach() que sirven para agregar o remover observadores en tiempo de ejecución.
Observer: define la interfaz que sirve para notificar a los observadores los cambios realizados en el Subject.
SubjectConcreto: almacena el estado que es objeto de interés de los observadores y envía un mensaje a sus observadores cuando su estado cambia.
ObserverConcreto: mantiene una referencia a un SubjectConcreto. Almacena el estado del Subject que le resulta de interés. Implementa la interfaz de actualización de Observer para mantener la consistencia entre los dos estados.

 Ejemplo

Vamos a suponer un ejemplo de una Biblioteca, donde cada vez que un lector devuelve un libro se ejecuta el método devuelveLibro(Libro libro) de la clase Biblioteca.
Si el lector devolvió el libro dañado entonces la aplicación avisa a ciertas clases que están interesadas en conocer este evento:

Cada clase que quiera observar el cambio del estado en el libro deberá implementar la siguiente interface y darle lógica al método update:





Veamos el subject:


La biblioteca es quién dispara el evento. Seguramente el estado de un libro no estará en formato String, pero no viene al caso.


Veamos como funciona:


Consecuencias
  • Permite modificar las clases subjects y las observers independientemente.
  • Permite añadir nuevos observadores en tiempo de ejecución, sin que esto afecte a ningún otro observador.
  • Permite que dos capas de diferentes niveles de abstracción se puedan comunicar entre sí sin romper esa división.
  • Permite comunicación broadcast, es decir, un objeto subject envía su notificación a todos los observers sin enviárselo a ningún observer en concreto (el mensaje no tiene un destinatario concreto). Todos los observers reciben el mensaje y deciden si hacerle caso ó ignorarlo.
  • La comunicación entre los objetos subject y sus observadores es limitada: el evento siempre significa que se ha producido algún cambio en el estado del objeto y el mensaje no indica el destinatario.

Temas a tener en cuenta.

Si los observadores pueden observar a varios objetos subject a la vez, es necesario ampliar el servicio update() para permitir conocer a un objeto observer dado cuál de los objetos subject que observa le ha enviado el mensaje de notificación.
Una forma de implementarlo es añadiendo un parámetro al servicio update() que sea el objeto subject que envía la notificación (el remitente). Y añadir una lista de objetos subject observados por el objeto observer en la clase Observer.
Si los objetos observers observan varios eventos de interés que pueden suceder con los objetos subjects, es necesario ampliar el servicio add() y el update() además de la implementación del mapeo subject-observers en la clase abstracta Subject. Una forma de implementarlo consiste en introducir un nuevo parámetro al servicio add() que indique el evento de interés del observer a añadir e introducirlo también como un nuevo parámetro en el servicio update() para que el subject que reciba el mensaje de notificación sepa qué evento ha ocurrido de los que observa.

Cabe destacar que Java tiene una propuesta para el patrón observer:
Posee una Interfaz java.util.Observer: una clase puede implementar la interfaz Observer cuando dicha clase quiera ser informada de los cambios que se produzcan en los objetos observados. Tiene un servicio que es el siguiente: void update (Observable o, Object arg)
Este servicio es llamado cuando el objeto observado es modificado.
Además Java nos ofrece los siguientes servicios:
void addObserver (Observer o)
protected void clearChanged()
int countObservers()
void deleteObserver (Observer o)
void deleteObservers()
boolean hasChanged()
void notifyObservers()
void notifyObservers (Object arg)
protected void setChanged()

Posee una clase llamada java.util.Observable: esta clase representa un objeto Subject.
Veamos el mismo ejemplo con el estandard de Java:




Publicar un comentario