Ing. del software B Il Pattern Observer Simone Magnolini.
-
Upload
demetrio-manzi -
Category
Documents
-
view
219 -
download
1
Transcript of Ing. del software B Il Pattern Observer Simone Magnolini.
Ing. del software B
Il Pattern “Observer”
Simone Magnolini
Definire una dipendenza uno a molti fra oggetti, in modo tale che se un
oggetto cambia il suo stato, tutti gli oggetti dipendenti da questo ricevano
una notifica e si aggiornino automaticamente.
Scopo
Un esempio concreto
Prendiamo ad esempio questa stessa presentazione:
L'uno: la presentazione, ha uno stato (il numero della slide ad esempio) che pubblica, per questo in generale si identifica come publisher o subject.
La relazione non è unidirezionale, chiunque può intervenire per cambiare lo stato della presentazione
I molti: le persone presenti in aula, sono “interessate” allo stato del soggetto che hanno sottoscritto di osservare (tramite il loro ingresso in aula) per questo si identificano come subscriber o observer
Doveri e responsabilità
Presentazione
Mantenere uno stato, cambiarlo, restituirlo
Inoltre in un qualche modo quando cambia stato deve comunicare la modifica avvenuta, come ad esempio...
Pubblico
Reagire al cambio di stato “nel modo opportuno”
Modificare lo stato di ciò che sta osservando
Struttura observer
Presentazione
getState()
setState()
statoPresentazione
Alunno 1
reagisci()
statoAlunno
Alunno N
reagisci()
statoAlunno
Alunno 2
reagisci()
statoAlunno
Struttura observer
Presentazione
getState()
setState()
statoPresentazione
Alunno 1reagisci()
statoAlunno
Alunno Nreagisci()
statoAlunno
Alunno 2reagisci()
statoAlunno
Ascoltatore
reagisci()
Struttura observer
Presentazione
getState()
setState()
statoPresentazione
Alunno 1reagisci()
statoAlunno
Alunno Nreagisci()
statoAlunno
Alunno 2reagisci()
statoAlunno
Ascoltatore
reagisci()
Lezione
aggiungi(Ascoltatore)
rimuovi(Ascoltatore)
notifica()
Struttura observer
Presentazione
getState()
setState()
statoPresentazione
Alunno 1reagisci()
statoAlunno
Alunno Nreagisci()
statoAlunno
Alunno 2reagisci()
statoAlunno
Ascoltatore
reagisci()
Lezione
aggiungi(Ascoltatore)
rimuovi(Ascoltatore)
notifica()
Struttura observer
ConcreteSubject
getState()
setState()
subjectstate
ConcreteObserverupdate()
observerState
Observer
update()
Subject
attach(Observer)
detach(Observer)
notify()
Anche conosciuto come
Publish-Subscribe
Dependents
Java Delegation Event Model
Intuitivamente correlato a tutti i paradigmi di programmazione “a eventi”
Classificazione
Comportamentale
Focalizzato sulle relazioni run-time tra oggetti
Il Pattern “Observer”
Viste multiple dello stato pubblicato
Più di un formato di visualizzazione
Devono essere coerenti
Viste multiple interattive, che permettono la modifica dello stato
Occorre aggiornare anche le altre viste
Devono essere coerenti
Paradigma a eventi (non c’entra per forza una GUI)
Es. il meccanismo dei trigger in una base di dati relazionale
Motivazione
A B C D44 33 333 88
ABCD
0
50
100
150
200
250
300
350
A B C D
Esempio classico
Se un’astrazione presenta due aspetti in cui uno è dipendente dall’altro. Separandoli è possibile riutilizzarli
Se cambiamenti ad un oggetto hanno ripercussioni su altri oggetti il cui numero è variabile, o comunque non è noto a priori
Se un oggetto deve inviare messaggi ad altri oggetti senza sapere esattamente di che tipo sono
legami di dipendenza deboli (disaccoppiamento)
Applicabilità
Partecipanti: Subject
“Conosce” tutti gli observer
Chiunque implementi l’interfaccia observer può osservare il soggetto
Offre metodi per:
L’aggiunta di un osservatore (attach)
La rimozione di un osservatore (detach)
In java potrebbe essere implementata come abstract
Senza istanze, ma con dei metodi implementati
Partecipanti: Observer
Fornisce un’interfaccia
Tutti gli osservatori devono ereditarla per ottenere gli aggiornamenti del soggetto
In java potrebbe essere implementata come interface
Senza istanze né metodi implementati
Partecipanti: ConcreteSubject
Memorizza lo stato che interessa ai ConcreteObserver
Lo ritorna, in generale, con il metodo getState() nel caso Java
NOTA: Bisogna chiamare notify() all’interno di setState()
Al termine della modifica di stato il cambiamento viene notificato a tutti gli osservatori, anche a chi l’ha
prodotto
Partecipanti: ConcreteObserver
Mantiene un riferimento ad un oggetto ConcreteSubject di interesseIn realtà un singolo osservatore può guardare più soggetti
Memorizza lo stato
Quello che dovrebbe essere sincronizzato/aggiornato
Implementa l’interfaccia Observer
Implementa il metodo update(), quest’ultimo aggiorna lo stato memorizzato per mantenere la sincronia
Collaborazioni: iscrizione
aConcreteSubject
aConcreteObserver
attach(this)
attach(this)
notify ()
update()
update()
anotherConcreteObserver
getState()
getState()
Collaborazioni: aggiornamento
aConcreteSubject
aConcreteObserver
setSate()
notify ()
update()
update()
anotherConcreteObserver
getState()
getState()
Conseguenze
Disaccoppiamento tra le classi
Il Subject conosce solo l’interfaccia Observer (non chi l’osserva)
Per ricevere le notifiche un oggetto qualunque deve solo implementare l’interfaccia Observer
Broadcast
I messaggi possono essere notificati a tutti gli Observer chiamando notify()
Si possono rimuovere e aggiungere Observer a piacere
Il problema degli update non attesi
Gli Observer non si conoscono
Non possono sapere i reali effetti di operazioni compiute sul Subject
Possono esserci effetti a cascata di aggiornamenti e sincronizzazioni,anche incompleti
Problemi implementativi
1) Tracciare le dipendenze
Mantenere le associazioni
Il Subject tiene traccia di tutti i propri Observer
Necessario per sapere a chi mandare le notifiche
Efficiente nel caso ideale (pochi Subject, molti Observer)
Il sovraccarico delle strutture dati può diventare significativo se la situazione è invertita (pochi Observer e
molti Subject)
Strutture associative per mappare Subject e Observer (es. Hash Table)
Risparmio dello spazio, ma penalità nel tempo
2) Tanti Subject
Tante cose da osservare
Un Observer può essere interessato alle notifiche di più Subject
Un oggetto che necessità di più strutture dati per funzionare
Es. Un grafico che rappresenta le relazioni tra due entità
In questo caso potrebbe essere utile passare l’oggetto come parametro della notifica per rendere evidente
chi è stato modificato
3) Responsabilità
Chi è il responsabile di iniziare l’invio di notifiche?
Il Subject
Le operazioni che modificano lo stato dell’oggetto chiamano notify()
L’Observer può ignorare il problema
Più operazioni di questo tipo causano molti update consecutivi
Possibile inefficienza
Sicuri problemi con il multithreading!
Gli Observer
Chiamano notify() quando hanno finito di modificare lo stato
Più efficiente, più facile gestire il multithreading
Più responsabilità per gli Observer, che a questo punto diventano dei client non più passivi del Subject
Meno sicuro
4) Distruttori
Distruzione del Subject
In generale, la soluzione migliore è notificare la situazione agli Observer
Non è detto che gli Observer debbano essere distrutti per forza
Se “osservano” più soggetti?
Modifica opportuna al distruttore della classe Subject
E IN JAVA?????
Altri problemi
Auto-consistenza del Subject
Prima del notify() tutti gli aggiornamenti devono essere completi
Non utilizzare protocolli specifici di aggiornamento
Modello push, il Subject inoltra informazioni sulla modifica
Più efficiente, ma meno riusabile
Modello pull, il Subject delega l’aggiornamento agli osservatori
Meno efficiente, ma più riusabile
Osservatori interessati
Per migliorare l’efficienza gli Observer potrebbero fornire al momento dell’iscrizione a cosa sono interessati del Subject
Quando ci sono troppi problemi
ChangeManager èun’istanza del patternMediator ed essendo uniconell’applicazione potrebbeessere un Singleton
Implementazione
ESEMPIO: Un count down java
import java.util.Observable;
import java.util.Observer;
public class Esempio{
public static void main(String[] args){
// istanzio l'oggetto osservatore e l'oggetto da osservare
Osservatore osservatore = new Osservatore();
Osservato osservato = new Osservato();
// aggiungo all'oggetto da osservare l'osservatore
osservato.addObserver(osservatore);
// faccio partire il conto alla rovescia
osservato.contoAllaRovescia(10);
}
}
Implementazione
class Osservato extends Observable {
public void contoAllaRovescia(int n) {
for ( ; n >= 0; n--) {
// l'oggetto e' cambiato
setChanged();
// notifico il cambiamento all'osservatore
notifyObservers(new Integer(n));
}
}
}
Implementazione
class Osservatore implements Observer {
public void update(Observable oggettoOsservato, Object obj) {
// ottengo il valore di n passato da notifyObservers ad update
int n = ((Integer)obj).intValue();
System.out.println("" + n);
}
}
Ultime note
In Java esistono le interfacce Observer e Observable
Sono “deprecated” dalla versione 1.1
Compatibilità retroattiva
Casi molto semplici, usi in cui il meccanismo a eventi è probabilmente eccessivo
Java Delegation Event Model
Si definiscono “listeners”, “event handlers”