Design patterns: Observer
L’Observer Pattern è un design pattern comportamentale che definisce una relazione uno-a-molti tra oggetti. Quando un oggetto cambia il proprio stato, tutti gli oggetti che lo osservano (notificati come osservatori) vengono automaticamente avvisati e aggiornati. Questo pattern è utile quando si desidera che diversi oggetti reagiscano automaticamente ai cambiamenti in un altro oggetto, mantenendo un accoppiamento debole tra i soggetti coinvolti.
Punti di Forza
- Disaccoppiamento: Mantiene un accoppiamento debole tra il soggetto osservato e gli osservatori, favorendo la modularità e la flessibilità del codice.
- Notifiche Automatiche: Gli osservatori vengono notificati automaticamente quando il soggetto cambia stato, senza che sia necessario un’interazione esplicita tra soggetto e osservatore.
- Facilità di Estensione: Aggiungere nuovi osservatori o soggetti non richiede modifiche agli oggetti esistenti, rendendo il sistema estendibile.
- Flessibilità: Permette di aggiungere dinamicamente osservatori a runtime, consentendo di modificare il comportamento del sistema senza modificarne la struttura.
- Applicazione in Sistemi Reattivi: È ideale per la realizzazione di sistemi reattivi, in cui le azioni di un oggetto devono propagarsi in modo efficiente e tempestivo su altri oggetti.
Caso d’Uso
Supponiamo di avere un sistema di notifiche per un blog. Quando un nuovo articolo viene pubblicato, tutti gli utenti iscritti devono essere notificati via email. Il blog è il soggetto che avvisa gli osservatori (gli utenti registrati) ogni volta che c’è un nuovo articolo.
Codice PHP
// Interfaccia per gli osservatori
interface Observer {
public function update($article);
}
// Interfaccia per il soggetto (Blog)
interface Subject {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
// Classe concreta del soggetto (Blog)
class Blog implements Subject {
private $observers = [];
private $latestArticle;
public function attach(Observer $observer) {
$this->observers[] = $observer;
}
public function detach(Observer $observer) {
$this->observers = array_filter($this->observers, function($o) use ($observer) {
return $o !== $observer;
});
}
public function publishArticle($article) {
$this->latestArticle = $article;
$this->notify();
}
public function notify() {
foreach ($this->observers as $observer) {
$observer->update($this->latestArticle);
}
}
}
// Classe concreta dell'osservatore (Utente)
class User implements Observer {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function update($article) {
echo "Notifica per {$this->name}: nuovo articolo pubblicato - {$article}\n";
}
}
// Esempio d'uso
// Creiamo un nuovo blog
$blog = new Blog();
// Creiamo alcuni utenti (osservatori)
$user1 = new User("Alice");
$user2 = new User("Bob");
// I due utenti si iscrivono alle notifiche del blog
$blog->attach($user1);
$blog->attach($user2);
// Viene pubblicato un nuovo articolo
$blog->publishArticle("Introduzione ai Design Patterns");
/* Output:
Notifica per Alice: nuovo articolo pubblicato - Introduzione ai Design Patterns
Notifica per Bob: nuovo articolo pubblicato - Introduzione ai Design Patterns
*/
Spiegazione
- Observer: L’interfaccia che definisce il metodo update(), il quale viene chiamato ogni volta che il soggetto (il blog) notifica un cambiamento.
- Subject: L’interfaccia per il soggetto osservato, con i metodi attach(), detach() e notify() per gestire gli osservatori e notificare i cambiamenti.
- Blog: Classe concreta che implementa il soggetto. Gestisce una lista di osservatori e notifica gli aggiornamenti quando viene pubblicato un nuovo articolo.
- User: Classe concreta dell’osservatore che implementa il metodo update() per ricevere le notifiche.