[Design patterns in Java] Observer
Il pattern Observer si utilizza quando occorre conoscere lo stato di un oggetto e si vuole ricevere una notifica ad ogni cambiamento dello stesso.
CLASSIFICAZIONE
Il pattern Observer è classificato tra i pattern comportamentali.
PROBLEMA E CAMPO DI APPLICAZIONE
Per conoscere lo stato di un oggetto è possibile interrogarlo periodicamente attraverso un meccanismo di polling, ma questa modalità è poco efficiente in quanto
- si genera un incremento del carico applicativo per gestire queste continue richieste
- si rischia di perdere degli eventi nell'intervallo tra due richieste consecutive
SOLUZIONE
La soluzione più semplice consiste nel lasciare che siano gli oggetti osservati a notificare ogni cambiamento a quelli interessati.
Infatti gli attori principali di questo pattern sono la classe o meglio l'interfaccia Subject
e la Observer
.
La prima darà vita agli oggetti di cui ci interessa conoscere lo stato, la seconda a quelli interessati al medesimo.
L'implementazione prevede che sia il Subject
a mantenere una lista di tutti gli Observer
a cui inviare una notifica ad ogni cambio di stato.
In questo modo ciascun Observer
non dovrà preoccuparsi di richiedere alcuna informazione autonomamente.
Il Subject dispone di due metodi pubblici (add(Observer o)
e remove(Observer o)
) che sono invocati per gestire la ricezione o meno delle notifiche.
public interface Subject {
public void add(Observer o);
public void remove(Observer o);
public void notify(Message m);
}
I nomi dei metodi possono cambiare ed in letteratura si possono trovare anche register()
/unregister()
oppure subscribe()
/unsubscribe()
.
L'interfaccia Observer
dispone di un unico metodo (update(Message m)
) richiamato dal Subject
nel momento in cui occorre notificare un cambio di stato.
public interface Observer {
public void update(Message m);
}
N.B. Nell'esempio proposto ipotizziamo che il ConcreteSubject
(ovvero la classe che implmenta l'interfaccia Subject
) sia rappresentato dalla classe MessagePublisher
che invia dei messaggi a tutti gli Observer che si sono registrati. Quindi lo "stato" è rappresentato dallo stesso messaggio.
public class MessagePublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void add(Observer o) {
observers.add(o);
}
@Override
public void remove(Observer o) {
observers.remove(o);
}
@Override
public void notify(Message m) {
for (Observer o : observers) {
o.update(m);
}
}
}
Per testare il tutto utilizziamo una classe Client
così strutturata
public class Client {
public static void main(String[] args) {
ConcreteObserver o1 = new ConcreteObserver("Observer 1");
MessagePublisher p = new MessagePublisher();
p.add(o1);
p.notify(new Message("First Message"));
p.remove(o1);
p.notify(new Message("Second Message"));
}
}
Prima di tutto introduciamo un nuovo Observer (ConcreteObserver
) o1
e un Subject (MessagePublisher
) p
.
Aggiungiamo o1
alla lista degli Observer gestiti dal Subject quindi con la sola chiamata al metodo notify(...)
è possibile inviare una notifica con l'aggiornamento dello stato (in questo caso un semplice messaggio) a tutti gli Observer registrati.
Dopo aver rimosso l'Object dalla lista quest'ultimo non sarà più in grado di ricevere ulteriori notifiche.
[VIDEO]