Ingeniería del Software II
Unicomfacauca
OBSERVER (OBSERVADOR)
Resumen
El patrón Observer es útil para diseñar un modelo de comunicación consistente entre un conjunto de
objetos dependientes y un objeto del que dichos objetos dependen. Esto permite que los objetos
dependientes tengan su estado, sincronizado con el objeto del cual dependen. El conjunto de objetos
dependientes se les llama observadores (observers) y el objeto del que ellos dependen se le llama sujeto
(subject).
Descripción
El patrón Observer es útil para diseñar un modelo de comunicación consistente entre un conjunto de
objetos dependientes y un objeto del que dichos objetos dependen. Esto permite que los objetos
dependientes tengan su estado, sincronizado con el objeto del cual dependen. El conjunto de objetos
dependientes se les llama observadores (observers) y el objeto del que ellos dependen se le llama sujeto
(subject).
Un observador típico es un objeto con interés o dependencia en el estado del sujeto. Un sujeto puede
tener más de un observador. Cada uno de los observadores necesita conocer cuándo el sujeto sufre un
cambio de estado.
El sujeto no puede mantener una lista estática de observadores. Por lo tanto, cualquier objeto con
interés en el estado del sujeto necesita explícitamente registrarse como un observador del sujeto. En
todo momento, cuando el sujeto sufre un cambio de estado, notifica a todos sus observadores
registrados. Después de recibir la notificación del sujeto, cada observador consulta el sujeto para
sincronizar su estado. De esta manera el sujeto se comporta como un publicador, publicando mensajes
con todos sus observadores suscritos.
En otras palabras, el escenario contiene uno-a-muchas relaciones entre un sujeto y el conjunto de
observadores. En todo momento cuando la instancia del sujeto sufre un cambio de estado, todos sus
observadores dependientes son notificados y se actualizan así mismos. Cada uno de los observadores
tienen que registrarse con el sujeto para poder ser notificado cuando hay un cambio de estado en el
sujeto. Un observador se puede registrar o suscribir con múltiples sujetos. En todo momento un
observador que ya no le interesa ser notificado, simplemente se puede des-registrar del sujeto.
Para que este mecanismo funcione:
• El sujeto debe suministrar una interface para registrar y des-registrar los cambios y
notificaciones.
• Una de las dos consignas debe ser verdadera:
◦ En el modelo, el sujeto debe suministrar una interface que active los observadores para
consultar el sujeto información del estado para poder actualizar su estado.
◦ En el modelo, el sujeto debe enviar la información de estado que los observadores pueden
estar interesados.
• Los observadores deben suministrar una interface para recibir notificaciones del sujeto.
La Figura 1, muestra la estructura de la lista de requisitos del patrón observer. De este diagrama se debe
1
Ingeniería del Software II
Unicomfacauca
tener en cuenta:
• Todos los sujetos esperan proveer la implementación de una interfaz similar a la interfaz
Observable.
• Todos los observadores esperan esperan tener una interfaz similar a la interfaz Observer.
Bajo este esquema
diferentes
observadores pueden ser adicionados dinámicamente.
Ejemplo
A continuación se presenta un ejemplo muy sencillo que ilustra la aplicación del patrón observer. El
Sujeto es un contador. El contador mantiene un valor entero en el rango desde 0 hasta máximo, donde
máximo se establece en el constructor del objeto. La clase dispone de métodos para modificar el valor y
para acceder al estado (es estado lo conforman los valores de los atributos: valor y máximo).
A continuación se muestra una tabla que resume las clases que intervienen en la aplicación, su rol y la
funcionalidad, acorde a la Figura 1.
Tabla 1: Clases del ejemplo - Patrón Observer
Clase Rol Funcionalidad
Contador Sujeto Mantiene un valor entero en el rango desde 0 hasta máximo
Observable Observable Clase abstracta que representa los objetos susceptibles de ser
observados. Incorpora métodos para agregar y eliminar observadores y un
método de notificación. La asociación Observable-Observadores se
implementa mediante un vector de observadores.
Observador Observador Los observadores deben implementar la interfaz Observador, es decir,
tienen un método actualizar() para reaccionar a cambios del sujeto.
Observador ConcreteOb Observador muy simple que ni siquiera consulta el estado del sujeto.
Concreto1 server
Observador ConcreteOb Un ejemplo de observador concreto de la clase contador (sujeto)
2
Ingeniería del Software II
Unicomfacauca
Concreto2 server
Observador ConcreteOb Un ejemplo de observador concreto de la clase contador (sujeto)
Concreto3 server
ClienteMain Cliente Un Cliente sencillo que prueba la ejecución del patrón
La Figura 2 muestra el diagrama de clases de la aplicación.
Código fuente en Java
A continuación el código fuente en java.
/**
* Ejemplo de sujeto observable o sujeto concreto. Es una clase que mantiene un
valor entero en
* el rango 0..maximo, donde maximo se establece en la construccion. La clase
* dispone de metodos para modificar el valor y para acceder al estado
* (valor, maximo). Extiende la clase observable heredando su
*/
public class Contador extends Observable {
// Atributos privados que mantienen el estado del contador
private int valor;
private int maximo;
/*
* El constructor inicializa el estado del objeto: el maximo y elvalor
* inicial, siempre en el rango 0..maximo. Adicionalmente,inicializa la
* parte de Observable que tiene un Contador...
*/
public Contador(int valor, int maximo) {
super();
[Link] = maximo;
[Link] = enRango(valor);
}
// Este metodo privado asegura que un valor n esta entre 0..maximo
3
Ingeniería del Software II
Unicomfacauca
private int enRango(int n) {
if (n < 0) {
return 0;
} else if (n > maximo) {
return maximo;
} else {
return n;
}
}
/**
* Estos dos metodos permiten el acceso al estado del contador
* @return el valor del contador
*/
public int getValor() {
return valor;
}
public int getMaximo() {
return maximo;
}
/*
* Este metodo afecta al estado: primero se modifica de forma consistenteel
* estado y despues se notifica a los observadores del cambio
*/
public void incrementarContador(int n) {
valor = enRango(valor + n);
notificarObservadores();
}
}
/**
* Esta clase abstracta representa los objetos susceptibles de ser
* observados. Incorpora metodos para agregar y eliminar observadores
* y un metodo de notificacion. La asociacion Observable-Observadores
* se implementa mediante un vector de observadores
*/
import [Link];
public abstract class Observable {
// Este atributo privado mantiene el vector con los observadores
private ArrayList<Observador> observadores;
// El constructor crea el vector con la asociacion Observable-Observador
public Observable() {
observadores = new ArrayList<Observador>();
}
// Agregar y eliminar sencillamente operan sobre vector _observadores...
public void agregarObservador(Observador o) {
[Link](o);
}
public void eliminarObservador(Observador o) {
[Link](o);
}
// Notificacion: Para cada observador se invoca el método actualizar().
public void notificarObservadores() {
4
Ingeniería del Software II
Unicomfacauca
for (Observador o : observadores) {
[Link]();
}
}
}
/**
* Los observadores deben implementar la siguiente interfaz, es decir,
* tienen un metodo actualizar() para reaccionar a cambios del sujeto
*/
public interface Observador {
public void actualizar();
}
/**
* Observador muy simple que ni siquiera consulta el estado del sujeto.
*
*/
public class ObservadorConcreto1 implements Observador {
public void actualizar() {
[Link]("Observador concreto simple recibe actualizar!");
}
}
/**
* Un ejemplo de observador concreto de la clase contador.
*
*/
public class ObservadorConcreto2 implements Observador {
// Mantiene la asociacion con el contador
private Contador contador;
// El constructor de Medidor establece la asociacion entre Medidor-Contador
public ObservadorConcreto2(Contador contador) {
[Link] = contador;
}
/*
* Tras ser notificado de un cambio, un observador Medidor accedeal estado
* del Contador utilizando la asociacion
*/
public void actualizar() {
[Link]("Valor del contador de ObservadorConcreto2: " +
[Link]());
}
}
/**
* Un ejemplo de observador concreto de la clase contador.
*
*/
public class ObservadorConcreto3 implements Observador {
// Mantiene asociacion con el sujeto observable
private Contador contador;
5
Ingeniería del Software II
Unicomfacauca
// El constructor establece la asociacion entre ValorContador-Contador
public ObservadorConcreto3(Contador contador) {
[Link] = contador;
}
/*
* Tras ser notificado de un cambio, un observador ValorContador accedeal
* estado del Contador utilizando la asociacion
*/
public void actualizar() {
[Link]("Valor del contador de ObservadorConcreto3 es "
+ [Link]());
}
}
/**
* Cliente
*
*/
public class ClienteMain {
public static void main(String... argv) {
Contador c = new Contador(100, 255);
ObservadorConcreto1 oc1 = new ObservadorConcreto1();
[Link](oc1);
ObservadorConcreto2 oc2 = new ObservadorConcreto2(c);
[Link](oc2);
ObservadorConcreto3 oc3 = new ObservadorConcreto3(c);
[Link](oc3);
[Link]("Primer Incremento");
[Link](5);
[Link]("\nSegundo Incremento");
[Link](5);
[Link](oc1);
[Link]("\nTercer Incremento");
[Link](5);
}
}
La ejecución del cliente debe mostrar la siguiente información por la consola:
Primer Incremento
Observador concreto simple recibe actualizar!
Valor del contador de ObservadorConcreto1: 105
Valor del contador de ObservadorConcreto3 es 105
Segundo Incremento
Observador concreto simple recibe actualizar!
Valor del contador de ObservadorConcreto1: 110
Valor del contador de ObservadorConcreto3 es 110
Tercer Incremento
6
Ingeniería del Software II
Unicomfacauca
Valor del contador de ObservadorConcreto1: 115
Valor del contador de ObservadorConcreto3 es 115