Il Pattern Observer è uno dei pattern di progettazione comportamentali. Il pattern Observer è utile quando si è interessati allo stato di un oggetto e si desidera essere notificati ogni volta che avviene una modifica. Nel pattern Observer, gli oggetti che osservano lo stato di un altro oggetto sono chiamati Observer e l’oggetto che viene osservato è chiamato Subject.
Pattern di Progettazione Observer
Secondo GoF, l’intento del pattern di progettazione Observer è;
Definire una dipendenza uno-a-molti tra oggetti in modo che quando un oggetto cambia stato, tutti i suoi dipendenti vengano notificati e aggiornati automaticamente.
Il soggetto contiene un elenco di osservatori da notificare di qualsiasi cambiamento nel suo stato, quindi dovrebbe fornire metodi tramite i quali gli osservatori possono registrarsi e annullare la registrazione. Il soggetto contiene anche un metodo per notificare tutti gli osservatori di eventuali cambiamenti e può inviare l’aggiornamento durante la notifica dell’osservatore o fornire un altro metodo per ottenere l’aggiornamento. L’osservatore dovrebbe avere un metodo per impostare l’oggetto da monitorare e un altro metodo che verrà utilizzato dal soggetto per notificarli di eventuali aggiornamenti. Java fornisce una piattaforma integrata per l’implementazione del pattern Observer tramite la classe java.util.Observable e l’interfaccia java.util.Observer. Tuttavia, non è ampiamente utilizzato perché l’implementazione è molto semplice e nella maggior parte dei casi non vogliamo finire per estendere una classe solo per implementare il pattern Observer, poiché Java non fornisce l’ereditarietà multipla nelle classi. Java Message Service (JMS) utilizza il pattern di progettazione Observer insieme al pattern Mediator per consentire alle applicazioni di sottoscriversi e pubblicare dati ad altre applicazioni. I framework Model-View-Controller (MVC) utilizzano anche il pattern Observer, in cui il Model è il Subject e le Views sono osservatori che possono registrarsi per essere notificati di eventuali cambiamenti al modello.
Esempio di pattern Observer in Java
Per il nostro esempio di programma Java sul pattern observer, implementeremo un semplice argomento e gli osservatori potranno registrarsi a questo argomento. Ogni volta che verrà pubblicato un nuovo messaggio sull’argomento, tutti gli osservatori registrati verranno notificati e potranno consumare il messaggio. In base ai requisiti del soggetto, ecco l’interfaccia di base del soggetto che definisce i metodi contrattuali da implementare da parte di qualsiasi soggetto concreto.
package com.journaldev.design.observer;
public interface Subject {
//metodi per registrare e annullare la registrazione degli osservatori
public void register(Observer obj);
public void unregister(Observer obj);
//metodo per notificare gli osservatori del cambiamento
public void notifyObservers();
//metodo per ottenere gli aggiornamenti dal soggetto
public Object getUpdate(Observer obj);
}
Successivamente creeremo il contratto per l’osservatore, ci sarà un metodo per collegare il soggetto all’osservatore e un altro metodo da utilizzare dal soggetto per notificare eventuali cambiamenti.
package com.journaldev.design.observer;
public interface Observer {
//metodo per aggiornare l'osservatore, utilizzato dal soggetto
public void update();
//collegamento con il soggetto da osservare
public void setSubject(Subject sub);
}
Ora il nostro contratto è pronto, procediamo con l’implementazione concreta del nostro argomento.
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;
//viene utilizzata la sincronizzazione per assicurarsi che gli osservatori registrati dopo la ricezione del messaggio non vengano notificati
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;
}
//metodo per pubblicare un messaggio sull'argomento
public void postMessage(String msg){
System.out.println("Message Posted to Topic:"+msg);
this.message=msg;
this.changed=true;
notifyObservers();
}
}
L’implementazione del metodo per registrare e annullare la registrazione di un osservatore è molto semplice, il metodo aggiuntivo è postMessage() che verrà utilizzato dall’applicazione client per inviare un messaggio di tipo String al topic. Si noti la variabile booleana per tenere traccia dei cambiamenti nello stato del topic e utilizzata per notificare gli osservatori. Questa variabile è necessaria affinché, se non ci sono aggiornamenti e qualcuno chiama il metodo notifyObservers(), non vengano inviate notifiche false agli osservatori. Si noti inoltre l’uso di sincronizzazione nel metodo notifyObservers() per assicurarsi che la notifica venga inviata solo agli osservatori registrati prima che il messaggio venga pubblicato nel topic. Ecco l’implementazione degli osservatori che monitoreranno il soggetto.
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;
}
}
Si noti l’implementazione del metodo update() che chiama il metodo getUpdate() del soggetto per ottenere il messaggio da consumare. Avremmo potuto evitare questa chiamata passando il messaggio come argomento al metodo update(). Ecco un semplice programma di test per consumare la nostra implementazione del topic.
package com.journaldev.design.observer;
public class ObserverPatternTest {
public static void main(String[] args) {
//crea il soggetto
MyTopic topic = new MyTopic();
//crea gli osservatori
Observer obj1 = new MyTopicSubscriber("Obj1");
Observer obj2 = new MyTopicSubscriber("Obj2");
Observer obj3 = new MyTopicSubscriber("Obj3");
//registra gli osservatori al soggetto
topic.register(obj1);
topic.register(obj2);
topic.register(obj3);
//collega l'osservatore al soggetto
obj1.setSubject(topic);
obj2.setSubject(topic);
obj3.setSubject(topic);
//controlla se ci sono aggiornamenti disponibili
obj1.update();
//invia ora un messaggio al soggetto
topic.postMessage("New Message");
}
}
Quando eseguiamo il programma sopra, otteniamo il seguente output.
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
Diagramma delle classi del pattern Observer di Java
Il pattern di progettazione Observer è anche chiamato pattern di pubblicazione-sottoscrizione. Alcune delle sue implementazioni sono:
- java.util.EventListener in Swing
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
Questo è tutto per il pattern di progettazione Observer in Java, spero che ti sia piaciuto. Condividi il tuo amore con commenti e condividerlo con gli altri.
Source:
https://www.digitalocean.com/community/tutorials/observer-design-pattern-in-java