32
Pattern Observer

Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Pattern Observer

Page 2: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Il pattern Observer

• Il pattern Observer entra in gioco quando diversi oggetti devono conoscere i cambiamenti di stato di un oggetto particolare

• C'è’ un oggetto che deve essere costantemente monitorato (detto subject) da altri oggetti che osservano i i cambiamenti di quest'ultimo (detti observers).

• Il pattern Observer è di tipo comportamentale

Page 3: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti agli oggetti che devono essere avvisati (ConcreteObservers) tramite l’invocazione a un loro metodo, presente nella interfaccia che devono implementare (Observer).

Meccanismo del pattern Observer

Page 4: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Il pattern Observer

Il problema affrontato

Il pattern Observer trova applicazione nei casi in cui diversi oggetti (Observer) devono conoscere lo stato di un oggetto (Subject)

Motivazione

Mantenere la consistenza tra oggetti collegati, riducendo però l'accoppiamento tra di essi

Page 5: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Struttura del pattern Observer

Page 6: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

PartecipantiInterfaccia Subject Definisce la classe che deve essere “osservata”, conosce i suoi osservatori (in qualsiasi numero). Fornisce operazioni per l’addizione e cancellazione di oggetti osservatori

Interfaccia Observer. Specifica una interfaccia per la notifica di eventi agli oggetti interessati ad un Subject.

ConcreteSubject: Invoca le operazioni di notifica ereditate dal Subject, quando devono essere informati i ConcreteObserver dei suoi cambiamenti.

ConcreteObserver: Implementa l’operazione di aggiornamento dell'Observer.

Page 7: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Applicabilità del pattern Observer

Usare il pattern Observer quando:• In un problema ci sono due aspetti tra loro

dipendenti, che possono essere rappresentati come classi che possono essere usati indipendentemente tra loro

• Quando il cambiamento di un oggetto provoca un cambiamento in un altro oggetto

• Quando un oggetto ha la necessità di comunicare con altri oggetti, senza fare assunzioni sugli altri oggetti

Page 8: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Il pattern Observer in Java

Nel package java.util sono presenti la classe Observable (soggetto) e l'interfaccia Observer. La classe Observable registra gli osservatori e notifica i cambiamenti avvenuti agli Observer attraverso il metodo notifyObservers(Object args) preceduto da una chiamata al metodo setChanged() :

public class Subject extends Observable {public void startProcess() {

setChanged(); notifyObservers("Processo iniziato"); //== do somethingsetChanged(); notifyObservers("Processo concluso");}

} Gli Observer sono conservati con un Vector

Page 9: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

l'interfaccia Observer contiene un unico metodo update:

class Osservatore implements Observer { public void update(Observable obs, Object args) {… }} Il metodo update ricevere un argomento (args) per scopi

generali, e il riferimento all'oggetto Observable che ha notificato l'evento.

Un Observer può a sua volta registrarsi a più Subject.

Page 10: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Metodi di Subjectvoid addObserver( Observer o ): registra l’ Observer nel suo elenco

interno di oggetti da notificare.protected void setChanged(): registra il cambiamento di stato

boolean hasChanged(): restituisce true se l’oggetto ha cambiato stato (setChanged)

void notifyObservers(): se l’oggetto è cambiato notifica tutti gli Observer poi chiama il metodo clearChanged per segnare che l’oggetto è nello stato “non cambiato”.

void notifyObservers( Object arg ): oltre alla notifica invia ad ogni Observer un oggetto come secondo parametro del metodo update.

protected void clearChanged(): impone lo stato “non cambiato”

int countObservers(): il numero di Observer registrati.void deleteObservers(): cancella l’elenco degli Observer registrati.void deleteObservers(Observer o): cancella un Observer o

dall’elenco degli observer.

Page 11: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Come avviene la registrazione degli observer:

Osservatore obs = new Osservatore(); Subject subject = new Subject(); subject.addObserver(obs); subject.startProcess();

Page 12: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Pattern Observer conseguenze• Benefici

Minimizzazione dell'accoppiamento tra Observer e Subject, che possono essere usati indipendentemente gli uni dagli altri. Gli Observer possono essere aggiunti senza modificare il Subject. Il Subject conosce solo la lista dei suoi Observer, e non le classi concrete degli Observer, ma solo l'intefaccia. Subject e Observer possono appartenere a diversi livelli di astrazione.

• Event Broadcasting, gli observer possono essere aggiunti a run time e possono regolarsi se reagire o meno ad una notifica del subject

Page 13: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

SvantaggiPossibile cascata di notifiche. Poiché gli observer mutuamente si ignorano, una richiesta di modifica può avere effetti incontrollati, scatenando la reazione degli altri observer.

Essendo molto semplice l'interfaccia di notifica, risulta ostico stabilire il tipo di modifica che è avvenuta nel subject, e quindi per gli Observer regolarsi di conseguenza

Page 14: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Dettagli di implementazione

• Come il subject conserva gli observer

Array, Collection (LinkedList) • Come realizzare un meccanismo di osservazione di

più Subject (Observer registrato a più Subject)?

I metodo update deve notificare anche la natura del Subject (args->Object)

• Chi richiede le notifiche? Il Subject stesso, quando cambia lo stato; gli Observer, in conseguenza delle loro necessità (in questo modo si eviterebbero le notifiche inutili) ; oppure un terzo attore

Page 15: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

• Assicurarsi che i Subject effettuino le notifiche dopo i loro cambi di stato

• Quanta informazione passare nei metodi update? – Modalità push → il Subject invia informazioni

dettagliate sulla notifica– Modalità pull, il Subject non ivia alcuna informazione

Nel primo caso gli Observer sono meno riusabili

• Gli Observer possono specificare alcuni eventi di interesse su cui ricevere le notifiche (modello publish – subscrive)

• Per far si che un Observer ricevi una notifica dopo che un certo numero di Subject abbia cambiato stato si può usare un mediator, che raccoglie le notifiche dei Subject, li elabora e poi li passa agli Observer

Page 16: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Esempio: downloader

Costruiamo una classe in grado di scaricare una risorsa da internet, pero’ di comunicare anche il proprio stato ad osservatori utilizzando il pattern Observer.

• Gli stati di interesse possono essere: 1)Stabilire la connessione alla risorsa,2)Il download della risorsa (lettura dello stream) 3)La fine del download4)Un problema durante lo scaricamento

Lo stato puo’ essere trasmesso, informa di oggetto, proprio attraverso l’ argomento del metodonotify che il subject invia agli observers comprendano il tipo di notifica che ricevono.

Page 17: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

public class MsgObserver { public final static int START = 0; public final static int DOWNLOAD = 1; public final static int READLINE = 2; public final static int END = 3; public final static int EXCEPTION = 4; public int code; public Object msg; public MsgObserver(int code, Object msg) { this.code = code; this.msg = msg; } }

Il Subject, oltre al tipo di messaggio, può anche inviare anche altre informazioni, come la percentuale di download raggiunta, oppure un oggetto di tipo Exception se si verifica un'eccezione.

Page 18: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

• La classe Observable (il Subject)

public class DownloadPageSubject extends Observable { private URL url; private String html = null; public DownloadPageSubject(String path) { try { url = new URL(path);}

catch(MalformedURLException ex) { changedState(new MsgObserver(MsgObserver.EXCEPTION, ex));

//Notifichiamo l'eccezione } } public String getHtml() { return html; } private void changedState(MsgObserver msg) { setChanged(); notifyObservers(msg); }

Page 19: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

//== Metodo download l'attività del subjectpublic void download() { try { changedState(new MsgObserver(MsgObserver.START, null)); //Inizio connessione URLConnection connection = url.openConnection(); changedState(new MsgObserver(MsgObserver.DOWNLOAD,null)); //Connessione avvenuta BufferedReader read = new BufferedReader( new InputStreamReader(connection.getInputStream())); String line = read.readLine(); while(line!=null) { changedState(new MsgObserver(MsgObserver.READLINE, line)); //Lettura di una riga line = read.readLine(); if (line!=null) { html+=line; } } changedState(new MsgObserver(MsgObserver.END, null)); //Fine processo } catch(IOException ex) { changedState(new MsgObserver(MsgObserver.EXCEPTION, ex)); //Notifichiamo l' eccezione }}}

Page 20: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Un possibile observer potrebbe essere un oggetto che da informazioni sullo stato del download stampando i messagi sulla console di java:

class ConsoleObserver implements Observer { public void update(Observable o, Object arg) { MsgObserver message = (MsgObserver)arg; if(message.code==MsgObserver.START) { System.out.println("Connesione in corso..."); } else if(message.code==MsgObserver.DOWNLOAD) { System.out.println("Connesione OK"); } else if(message.code==MsgObserver.END) { System.out.println("Download terminato"); } } }

Page 21: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

• Un'altro observer invece può essere una JtextArea (swing) che stampa solo le righe che man mano vengono lette, quindi in questo caso identifica solo i messaggi READLINE e stampa la stringa che il subject incapsula nell' oggetto MsgObserver:

class TextAreaObserver extends JTextArea implements Observer { public void update(Observable o, Object arg)

{ MsgObserver message = (MsgObserver)arg; if (message.code == MsgObserver.READLINE) super.append((String)message.msg+"\n"); }

Page 22: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Limitazioni del modello Java Observer

• La classe Observer impedisce di fatto che l'implementazione dell'Observer possa ereditare da qualche altra classe

• L'Observer e il Subject devono coesistere nello stesso thread

Page 23: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

• Per aggirare il problema dell'ereditarietà si puo' usarre il meccanismo della “Delegation”

Si crea uno SpecialSubject della gerarchia che contiene un oggetto Observable

Si delega il comportamento del Subject (Observable) di cui lo SpecialSubject ha bisogno al suo oggetto Observable (il delegato)

Si perfeziona (Override) il metodo dell'oggetto che deve essere osservato

Page 24: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Esempio: Observed Employee

class Employee { String name; double salary; Employee() { salary=0; name=""; } Employee(String _name, double _salary) { name=_name; salary=_salary; } public void raiseSalary(double amount) { salary+=amount; System.out.println("Employee:new salary:"+salary); }}

Supponiamo di dover realizzare in Observer che deve essere informato degli aumenti di stipendio di un impiegato

Page 25: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

class ObservedEmployee extends Employee { //== OGGETTO DELEGATO PER LE NOTIFICHE AGLI OBSERVER private Observable obs; public ObservedEmployee(String name, double salary) { super(name,salary); obs = new DelegatedObservable(); } public Observable getObservable() {return obs;} public void raiseSalary(double amount) { //== METODO DA MONITORARE CON NOTIFICHE AGLI OBSERVER super.raiseSalary(amount); obs.setChanged(); obs.notifyObservers(new Double(amount)); }}

Creiamo una sottoclasse di Employee che possiede un oggetto Observable, cui deleghiamo il meccanismo di notifica

Page 26: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

L'utilizzo diretto dell' oggetto Observable, cui deleghiamo il meccanismo di notifica, non è in realtà possibile perché i metodi setChanged e clearChanged che servono per il meccanismo del pattern, sono protetti, non pubblici. Quindi non possono essere utilizzati in una classe che non sia ereditata da Obervable.SoluzioneCreare una classe DelegateObservable e fare l'ovverride dei metodi protected modificando la loro visibilità a public

Page 27: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

class DelegatedObservable extends Observable { public void clearChanged() { super.clearChanged(); } public void setChanged() { super.setChanged();}}//== use del delegateObservableclass ObservedEmployee extends Employee {... private DelegatedObservable obs;...}class SalaryObserver implements Observer { private double salary_change; public SalaryObserver() { salary_change = 0; }public void update(Observable obj, Object arg) { if (arg instanceof Double) { salary_change = ((Double)arg).doubleValue(); System.out.println("salary amount variation:" + salary_change); } else { System.out.println("SalaryObserver: Unkonwn change!"); } }}

Page 28: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

public class test {public static void main(String args[]) { //== Crea il Subject e Observers. ObservedEmployee e = new ObservedEmployee("A.Bell", 1200); SalaryObserver salaryObs = new SalaryObserver(); //== Add those Observers! e.getObservable().addObserver(salaryObs); //== change and notify Subject. e.raiseSalary(200);}

}

Page 29: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

• E' possibile completare la classe ObservedEmployee con altri metodi di Observable, in modo da avere una implementazione più sicura e controllata.

public void addObserver(Observer o) { obs.addObserver(o); }public void deleteObserver(Observer o) { obs.deleteObserver(o);}

In questo modo ObservedEmployee farebbe da wrapper per il suo contenuto Observable senza esporlo direttamente

Page 30: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Il modello ad Eventi di Awt

• Il package “Abstract Window Toolkit” di Java (1.1) mette a disposizione una serie di interfacce e classi per la programmazione delle interfacce grafiche. Swing che è parte della JFC (Java Foundation Class, da Java 2) è un versione più sofisticata di GUI, ma non supportata da tutte le distribuzioni Java

Page 31: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

ActionListenerAdjustmentListenerItemListenerTextListenerMouseMotionListenerWindowListener

ComponentListenerContainerListenerFocusListenerKeyListenerMouseListener

Java (da 1.1) adotta un modello per gli eventi della GUI proprio basato sul pattern Observer

Gli event source sono i componenti che nella GUI possono generare eventi (->ConcreteSubject)Gli oggetti cui devono essere notificati gli eventi si chiamano event listeners (->ConcreteObserver)Rispetto al pattern Observer, che prevede una sola interfaccia, il modello eventListner prevede 11 differenti interfacce di eventListner, dedicate a diverse famiglie di eventi

Page 32: Pattern Observer - Libero.it...Il pattern “Observer” assegna il compito di notificare i suoi cambi di stato all’oggetto monitorato stesso (Subject), attraverso dei riferimenti

Questi Listener hanno dei metodi specializzati che devono essere implementati (in quanto interfacce), mentre può accadere che un event listner sia interessato ad un evento in particolare (es Window Closing), o comunque a non tutti gli eventi dell'interfaccia.

Java fornisce delle classi “adapter” per assecondare queste richieste: La classe WindowAdapter implementa l'interfaccia WindowListner fornendo una implementazione dummy (vuota) per ciascuno dei metodi della interfaccia. La classe che eredita da WindowAdapter può specificare (override) solo i metodi di interesse.

(es)