Observer pattern: cosa si nasconde dietro l’Observer design pattern?

Per la programmazione di software bisogna considerare diversi aspetti: il prodotto finale non solo deve avere le funzioni desiderate, ma anche un codice sorgente il più leggibile e comprensibile possibile. Il tutto deve avvenire con il minimo sforzo, in particolare quando i programmi o parti di essi sono progettati con funzioni o elementi ricorrenti. Per questo scopo, i cosiddetti pattern o schemi GoF (“Gang of Four”) offrono una serie di modelli risolutivi predefiniti per diverse classi di problemi durante la fase di creazione di software.

Oltre ad altri pattern noti, come il Visitor pattern o il Singleton pattern, anche il cosiddetto Observer pattern fa parte di questa raccolta di pratici schemi progettuali che permettono di semplificare notevolmente la programmazione di routine. Vi spiegheremo cosa comporta l’Observer design pattern (includendo una rappresentazione grafica in UML) e vi illustreremo i punti forti e deboli di questo schema.

Cos’è l’Observer pattern?

L’Observer design pattern, abbreviato in Observer pattern, è uno tra gli schemi più amati per il design di software informatici. Presenta la possibilità di definire una dipendenza da uno a molti, quindi tra due o più oggetti, per comunicare le modifiche complessive a un oggetto preciso nel modo più semplice e rapido possibile. A tal fine, qualsiasi oggetto, che in questo caso agisce come Observer o osservatore, può registrarsi con un altro oggetto. Quest’ultimo, che in questo caso si definisce soggetto, informa gli osservatori registrati non appena ci sono delle modifiche o degli aggiustamenti.

Come già accennato, anche l’Observer pattern fa parte degli schemi GoF pubblicati nel 1994 nel “Design Patterns: Elements of Reusable Object-Oriented Software”. Si tratta di più di 20 schemi risolutivi per il design di software che svolgono ancora oggi un ruolo importante per la concezione e l’elaborazione di applicazioni informatiche.

Scopo e funzionamento dell’Observer pattern

L’Observer pattern lavora con due tipi di attori: da una parte troviamo il subject (soggetto), ossia un oggetto il cui stato deve essere osservato a lungo termine. Dall’altra parte troviamo invece gli oggetti che osservano (Observer o osservatori), che devono essere informati di tutte le modifiche apportate al subject.

Fatto

Di solito a un subject sono attribuiti più observer. In linea di massima, però, l’Observer pattern può essere applicato anche in caso di un solo oggetto che osserva.

Senza l’ausilio dell’Observer pattern, gli oggetti che osservano dovrebbero richiedere al subject aggiornamenti sullo stato a intervalli regolari; ciascuna richiesta implicherebbe i relativi tempi di calcolo e le risorse hardware necessarie. L’idea alla base dell’Observer pattern è di centralizzare il processo di informazione in un soggetto. Questo porta alla creazione di una lista in cui inserire gli osservatori. In caso di una modifica, il soggetto informa gli osservatori registrati nella lista, senza che questi debbano diventare attivi. Se non si desidera più un aggiornamento automatico dello stato di un determinato oggetto che osserva, esso viene semplicemente rimosso dalla lista.

N.B.

Per informare i singoli osservatori sono disponibili due modelli: nel modello push, il subject comunica lo stato modificato insieme alla notifica. Questo può però comportare problemi quando si trasmettono informazioni che l’observer non è in grado di utilizzare. Questo problema non si verifica nel metodo pull: qui il subject trasmette solo l’informazione di una modifica avvenuta. Gli osservatori possono richiedere infine informazioni dettagliate sullo stato modificato con una richiesta separata.

Rappresentazione grafica dell’Observer pattern (diagramma ULM)

Il funzionamento e l’uso di Design Pattern come l’Observer pattern sono spesso incomprensibili a un occhio esterno. Una rappresentazione grafica dello schema progettuale può semplificarne la comprensione. In particolare UML (Unified Modeling Language), il linguaggio di modellazione ampiamente diffuso, rende visibili e comprensibili le dipendenze sia per gli utenti tradizionali sia per quelli più esperti. Per questo motivo abbiamo deciso di attingere a UML come linguaggio rappresentativo per la seguente rappresentazione astratta dell’Observer pattern.

Quali sono i vantaggi e gli svantaggi dell’Observer design pattern?

Utilizzare l’Observer pattern per lo sviluppo di software può aiutare in molte situazioni. Il maggior vantaggio offerto da questo modello è l’elevato grado di indipendenza tra un oggetto osservato (subject) e gli oggetti che osservano e che si orientano allo stato attuale di quest’oggetto. L’oggetto osservato, ad esempio, non deve disporre di alcuna informazione sui suoi osservatori, perché l’interazione avviene indipendentemente dall’interfaccia dell’observer. Gli oggetti che osservano ricevono i relativi aggiornamenti in modo automatico, eliminando del tutto le inutili richieste dal sistema dell’Observer pattern (perché il subject non è cambiato).

Non è però sempre un vantaggio che il soggetto informi in modo automatico tutti gli osservatori registrati riguardo alle relative modifiche: le informazioni relative alle modifiche, infatti, vengono comunicate anche se irrilevanti per un observer. Questo può avere un impatto particolarmente negativo quando il numero di osservatori registrati è molto alto perché a questo punto lo schema dell’observer potrebbe impiegare molte risorse. Un altro problema dell’Observer pattern è che spesso nel codice sorgente del subject non è chiaro quali osservatori debbano ricevere le informazioni.

Observer pattern: dove si utilizza?

L’Observer design pattern è richiesto soprattutto per quelle applicazioni basate su componenti il cui stato

  • da una parte è osservato assiduamente dalle altre componenti,
  • dall’altra è sottoposto a modifiche regolari.

Tra i tipici casi d’uso troviamo le GUI (Graphical User Interfaces), che servono agli utenti per comunicare con un software attraverso un’interfaccia. Non appena i dati vengono modificati, devono essere aggiornati in tutte le componenti della GUI: uno scenario perfetto per la struttura soggetto-osservatore dell’Observer pattern. Anche i programmi che lavorano con record da visualizzare (tabelle classiche o diagrammi grafici) sfruttano l’ordine offerto dallo schema progettuale.

Per quel che riguarda il linguaggio di programmazione, in linea di massima non ci sono limitazioni precise per l’Observer design pattern. È importante soltanto che sia supportato il paradigma orientato all’oggetto per dare senso all’implementazione dello schema. Tra i linguaggi che ricorrono spesso a questo pattern troviamo C#, C++, Java, JavaScript, Python e PHP.

Observer pattern: esempio di utilizzo

L’implementazione dell’Observer design pattern nei diversi linguaggi di programmazione può variare a volte in modo significativo. Il principio alla base resta però sempre lo stesso: un oggetto preciso, ossia il suo stato, viene reso accessibile in modo più semplice ad altri oggetti. Un esempio concreto è offerto dal tutorial in tedesco dell’Observer Pattern su javabeginners.de, che vi illustreremo e sul quale ci orienteremo.

Nell’esempio, deve essere mostrato un testo pubblicato da un “narratore” nel relativo campo a più “ascoltatori”. La classe narratore (il subject) amplierà per questo scopo la classe Observable al metodo addObserver(). Questo permetterà di aggiungere ascoltatori (gli Observer). Inoltre sarà aggiunto il metodo setChanged(), che registra modifiche al subject e in caso di novità richiama notifyObservers() per informare tutti gli osservatori.

class narratore extends Observable {
	public narratore(){
		this.addObserver(new ascoltatore_1());
		this.addObserver(new ascoltatore_2());
		tell("Text");
	}
	public void tell(String info){
		if(countObservers()>0){
			setChanged();
			notifyObservers(info);
		}
	}
}

Gli observer richiedono inoltre un’implementazione dell’interfaccia osservatore che include il metodo udpate() e due argomenti: l’oggetto osservato e la modifica in forma di istanza di oggetto (ConcreteSubject).

class ascoltatore extends JFrame implements Observer{
	private JTextField field;
	public ascoltatore(){
		field1 = new JTextField("a");
		add(field);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(300, 50);
		setVisible(true);
	}
	public void update(Observable o, Object arg) {
		field.setText((String) arg);
	}
}
Hai trovato questo articolo utile?
Per offrirti una migliore esperienza di navigazione online questo sito web usa dei cookie, propri e di terze parti. Continuando a navigare sul sito acconsenti all’utilizzo dei cookie. Scopri di più sull’uso dei cookie e sulla possibilità di modificarne le impostazioni o negare il consenso.
Page top