L'Observer Pattern è basato su un concetto abbastanza semplice: un oggetto (observer) vuole essere avvisato del verificarsi di certe variazioni di stato di un altro oggetto (observable). Per far ciò si registra (subscribe
) per ricevere notifiche di queste variazioni.
In base alla definizione classica del pattern, l'observer deve avere la possibilità di annullare la registrazione se non è più interessato all'osservazione dell'observable.
Proviamo a spiegare il pattern con un esempio.
Supponiamo che un oggetto abbia il compito di diffondere messaggi che possono interessare altri oggetti. L'oggetto che diffonde i messaggi avrà il ruolo di observable mentre gli oggetti interessati ai messaggi rappresenteranno gli observer.
L'observable implementerà i metodi per registrare e annullare la registrazione ed un metodo per inserire un nuovo messaggio:
var centraleMessaggi = function() {
this.listaObserver = [];
};
centraleMessaggi.prototype = {
subscribe: function(callback) {
this.listaObserver.push(callback);
},
unsubscribe: function(callback) {
for (var i = 0; i < this.listaObserver.length; i++) {
if (this.listaObserver[i] === callback) {
this.listaObserver.splice(i, 1);
return;
}
}
},
nuovoMessaggio: function(msg) {
for (var i = 0; i < this.listaObserver.length; i++) {
this.listaObserver[i](msg);
}
}
};
I metodi subscribe()
e unsubscribe()
aggiungono e tolgono rispettivamente dall'array listaObserver
l'elemento passato come parametro. Nello specifico si tratta di una funzione da eseguire nel momento in cui arriva un nuovo messaggio.
La notifica dell'arrivo di un nuovo messaggio viene fatta dal metodo nuovoMessaggio()
che si occupa di scorrere l'elenco delle funzioni presenti in listaObserver
ed eseguirle passando il nuovo messaggio.
L'observer che vuole ricevere la notifica dell'arrivo di un nuovo messaggio dovrà quindi invocare il metodo subscribe()
passando la funzione di callback da eseguire al verificarsi dell'evento:
var cm = new centraleMessaggi();
cm.subscribe(function(msg) {
//...
});
Un oggetto che invia un messaggio invocherà semplicemente il metodo nuovoMessaggio()
, ignorando del tutto il fatto che ci siano altri oggetti in attesa di esso:
cm.nuovoMessaggio("Questo è un nuovo messaggio!");
Grazie alla flessibilità di JavaScript ed al ruolo speciale delle funzioni, possiamo sfruttare il meccanismo delle callback per implementare la notifica del verificarsi di un cambio di stato dell'observable. In altri linguaggi un observer verrebbe realizzato come un oggetto che implementa una specifica interfaccia e l'observable dovrebbe invocare il metodo previsto dall'interfaccia per notificare l'evento.
L'Observer Pattern è proprio il pattern utilizzato per l'implementazione della gestione degli eventi, tipica ad esempio nella interazione con l'interfaccia utente tramite l'HTML.