DESIGN PATTERN: OBSERVER

L’Observer è un pattern comportamentale che permette a un oggetto (Subject) di notificare automaticamente un insieme di oggetti (Observers) ogni volta che il suo stato cambia.
È alla base di molti sistemi basati su eventi e della programmazione reattiva.

QUANDO USARLO

  • Più oggetti devono reagire ai cambiamenti di stato di un altro oggetto.
  • Vuoi implementare sistemi di eventi o flussi di dati asincroni.
  • Vuoi disaccoppiare il publisher dai subscriber, evitando dipendenze dirette.

VANTAGGI

  • Broadcasting semplice verso più listener contemporaneamente.
  • Disaccoppiamento tra chi emette eventi e chi li gestisce.
  • Perfetto per UI reattive, flussi di dati in tempo reale e sistemi asincroni.
  • Supportato nativamente in librerie come RxJS.

POTENZIALI SVANTAGGI

  • Possibili memory leak se gli observer non vengono disiscritti.
  • La complessità aumenta con il numero di observer e interazioni.
  • Debug più complesso in sistemi con molti eventi concatenati.

STRUTTURA

SUBJECT -> OBSERVER 1, OBSERVER 2, …, OBSERVER N(stesso tipo) -> NOTIFICATION

CODICE

/**
 * Interfaccia comune per l'Observer(reazione agli eventi) 
 */
interface Observer {
	update(): void;
}

/**
 * Interfaccia del Subject(gestione delle iscrizioni)
 */
interface Subject {
	subscribe(observer: Observer): void;
	unsubscribe(observer: Observer): void;
	notify(): void;
}

/**
 * Interfaccia del Notification(chi invia la notifica)
 */
interface Notification{
	getMessage(): void;
}

/**
 * Implementazione concreta di Notification
 */
class MailNotification implements Notification{
	constructor(private text: string) { }

	getMessage(): void {
		console.log("Notifica mail:", this.text);
	}
}

/**
 * Implementazione concreta di Subject
 */
class MailSubject implements Subject {
	private observers: Set<Observer> = new Set();

	subscribe(observer: Observer): void {
		this.observers.add(observer);
	}

	unsubscribe(observer: Observer): void {
		this.observers.delete(observer);
	}

	notify(): void {
		this.observers.forEach(observer => observer.update());
	}
}

/**
 * OBSERVER
 * Implementazione concreta dell'observer
 * prende in input una notifica che verrà triggherata solo tramite il Subject(concreto)
 */
class MailObserver implements Observer {
	constructor(private notification: Notification) { }
	update(): void {
		this.notification.getMessage();
	}
}

//USO OBSERVER
const subject = new MailSubject();

const mail1 = new MailObserver(new MailNotification("Hai una nuova email"));
const mail2 = new MailObserver(new MailNotification("Aggiornamento account"));

subject.subscribe(mail1);
subject.subscribe(mail2);

//Notifica tutti
subject.notify();