Patrón Observer es uno de los patrones de diseño de comportamiento. El patrón de diseño Observer es útil cuando estás interesado en el estado de un objeto y deseas ser notificado cada vez que haya algún cambio. En el patrón Observer, los objetos que observan el estado de otro objeto se llaman Observadores y el objeto que está siendo observado se llama Sujeto.
Patrón de Diseño Observer
Según GoF, la intención del patrón de diseño Observer es;
Definir una dependencia de uno a muchos entre objetos, de modo que cuando un objeto cambie de estado, todos sus dependientes sean notificados y actualizados automáticamente.
Asunto contiene una lista de observadores a notificar sobre cualquier cambio en su estado, por lo que debería proporcionar métodos mediante los cuales los observadores puedan registrarse y cancelar su registro. El asunto también contiene un método para notificar a todos los observadores sobre cualquier cambio, y puede enviar la actualización mientras notifica al observador, o puede proporcionar otro método para obtener la actualización. El observador debe tener un método para establecer el objeto a observar y otro método que será utilizado por el Asunto para notificarles sobre cualquier actualización. Java proporciona una plataforma integrada para implementar el patrón Observer a través de la clase java.util.Observable y la interfaz java.util.Observer. Sin embargo, no es ampliamente utilizado porque la implementación es realmente simple y la mayoría de las veces no queremos terminar extendiendo una clase solo para implementar el patrón Observer ya que Java no proporciona herencia múltiple en las clases. El Servicio de Mensajes de Java (JMS) utiliza el patrón de diseño Observer junto con el patrón Mediador para permitir que las aplicaciones se suscriban y publiquen datos a otras aplicaciones. Los marcos de Modelo-Vista-Controlador (MVC) también utilizan el patrón Observer, donde el Modelo es el Asunto y las Vistas son observadores que pueden registrarse para ser notificados de cualquier cambio en el modelo.
Ejemplo de Patrón Observer en Java
Para nuestro ejemplo de programa en Java con el patrón observador, implementaríamos un tema simple y los observadores pueden registrarse en este tema. Cada vez que se publique un nuevo mensaje en el tema, se notificará a todos los observadores registrados y podrán consumir el mensaje. Según los requisitos de Subject, aquí está la interfaz base de Subject que define los métodos del contrato que deben ser implementados por cualquier subject concreto.
package com.journaldev.design.observer;
public interface Subject {
//métodos para registrar y anular el registro de observadores
public void register(Observer obj);
public void unregister(Observer obj);
//método para notificar a los observadores sobre cambios
public void notifyObservers();
//método para obtener actualizaciones del subject
public Object getUpdate(Observer obj);
}
A continuación, crearemos el contrato para Observer, habrá un método para adjuntar el Subject al observador y otro método que será utilizado por el Subject para notificar cualquier cambio.
package com.journaldev.design.observer;
public interface Observer {
//método para actualizar al observador, utilizado por el subject
public void update();
//adjuntar al subject para observar
public void setSubject(Subject sub);
}
Ahora nuestro contrato está listo, procedamos con la implementación concreta de nuestro tema.
package com.journaldev.design.observer;
import java.util.ArrayList;
import java.util.List;
public class MyTopic implements Subject {
private List observers;
private String message;
private boolean changed;
private final Object MUTEX= new Object();
public MyTopic(){
this.observers=new ArrayList<>();
}
@Override
public void register(Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if(!observers.contains(obj)) observers.add(obj);
}
}
@Override
public void unregister(Observer obj) {
synchronized (MUTEX) {
observers.remove(obj);
}
}
@Override
public void notifyObservers() {
List observersLocal = null;
//se utiliza la sincronización para asegurarse de que cualquier observador registrado después de recibir el mensaje no sea notificado
synchronized (MUTEX) {
if (!changed)
return;
observersLocal = new ArrayList<>(this.observers);
this.changed=false;
}
for (Observer obj : observersLocal) {
obj.update();
}
}
@Override
public Object getUpdate(Observer obj) {
return this.message;
}
//método para publicar un mensaje en el tema
public void postMessage(String msg){
System.out.println("Message Posted to Topic:"+msg);
this.message=msg;
this.changed=true;
notifyObservers();
}
}
La implementación del método para registrar y anular un observador es muy simple, el método adicional es postMessage() que será utilizado por la aplicación cliente para enviar un mensaje de cadena al tema. Observa la variable booleana para realizar un seguimiento de los cambios en el estado del tema y utilizarla para notificar a los observadores. Esta variable es necesaria para evitar que, si no hay actualización y alguien llama al método notifyObservers(), no envíe notificaciones falsas a los observadores. También observa el uso de sincronización en el método notifyObservers() para asegurarse de que la notificación se envíe solo a los observadores registrados antes de que se publique el mensaje en el tema. Aquí está la implementación de los Observadores que supervisarán el sujeto.
package com.journaldev.design.observer;
public class MyTopicSubscriber implements Observer {
private String name;
private Subject topic;
public MyTopicSubscriber(String nm){
this.name=nm;
}
@Override
public void update() {
String msg = (String) topic.getUpdate(this);
if(msg == null){
System.out.println(name+":: No new message");
}else
System.out.println(name+":: Consuming message::"+msg);
}
@Override
public void setSubject(Subject sub) {
this.topic=sub;
}
}
Observa la implementación del método update() donde se llama al método getUpdate() del Sujeto para obtener el mensaje a consumir. Podríamos haber evitado esta llamada pasando el mensaje como argumento al método update(). Aquí hay un programa de prueba simple para consumir nuestra implementación del tema.
package com.journaldev.design.observer;
public class ObserverPatternTest {
public static void main(String[] args) {
//crear sujeto
MyTopic topic = new MyTopic();
//crear observadores
Observer obj1 = new MyTopicSubscriber("Obj1");
Observer obj2 = new MyTopicSubscriber("Obj2");
Observer obj3 = new MyTopicSubscriber("Obj3");
//registrar observadores en el sujeto
topic.register(obj1);
topic.register(obj2);
topic.register(obj3);
//adjuntar observador al sujeto
obj1.setSubject(topic);
obj2.setSubject(topic);
obj3.setSubject(topic);
//verificar si hay alguna actualización disponible
obj1.update();
//ahora enviar mensaje al sujeto
topic.postMessage("New Message");
}
}
Cuando ejecutamos el programa anterior, obtenemos la siguiente salida.
Obj1:: No new message
Message Posted to Topic:New Message
Obj1:: Consuming message::New Message
Obj2:: Consuming message::New Message
Obj3:: Consuming message::New Message
Diagrama de Clase del Patrón Observador de Java
El patrón de diseño Observer también se llama patrón publicador-suscriptor. Algunas de sus implementaciones son;
- java.util.EventListener en Swing
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
Eso es todo para el patrón de diseño Observer en Java, espero que te haya gustado. Comparte tu amor con comentarios y compartiéndolo con otros.
Source:
https://www.digitalocean.com/community/tutorials/observer-design-pattern-in-java