Meccanismo del pattern Observer

Documenti analoghi
Il problema è trovare un modo nel quale gli eventi dell oggetto di riferimento, siano comunicati a tutti gli altri interessati.

Ingegneria del Software B. Il pattern Observer. Ex presentazione realizzata dallo studente Davide Ferrari nell a.a. 2009/2010

Tecniche di Progettazione: Design Patterns

Configurazione di una vs. Laboratorio di sistemi interattivi. Dal modello formale all implementazione

MVC: esempio in java. views e controllers in javax.swing

Design Pattern in Java

Corso di Reti di Calcolatori L-A

Marco Faella Elementi di programmazione di interfacce Grafiche. Il pattern OBSERVER.

Esempio su strutture dati dinamiche: ArrayList

Prova d Esame Compito A

Prova d Esame Compito A

Esempio su strutture dati dinamiche: ArrayList

Java. Classi Anonime In Java Da Java 1.1 si possono usare classi anonime per implementare interfacce. Espressioni Lambda. Implementazione Interfaccia

Classi Anonime In Java. Java. Espressioni Lambda. Implementazione Interfaccia

La classe java.lang.object

19 - Eccezioni. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Esempio su strutture dati dinamiche: ArrayList

Scope e visibilità per classi

Corso di Reti di Calcolatori LA

OLTRE LE CLASSI OLTRE LE CLASSI

OLTRE LE CLASSI OLTRE LE CLASSI OLTRE LE CLASSI OLTRE LE CLASSI. Alcune domande. Nella sua parte non statica, una classe

Lezione n.10 LPR Informatica Applicata RMI Approfondimenti Callback. 15/05/2012 Laura Ricci

Java SE 6. Programmazione grafica (3)

Esempi in Java di program.ne O-O

Corso di Algoritmi e Strutture dati Programmazione Object- Oriented in Java (Parte I)

Riassunto: cos è la OOP? classi astratte, interfacce, classi interne. Scaletta. Figura con area()? Figura senza area()? Stefano Mizzaro 1.

Implementare un'interfaccia

L Abstract Windowing Toolkit. Le GUI in Java. Il Frame. Cenni sull ereditarietà. Gianpaolo Cugola - Sistemi Informativi in Rete

NON ABBIAMO ANCORA CORRETTO LE PROVETTE!!!

Corso di Telematica II

18 - Classi parzialmente definite: Classi Astratte e Interfacce

17 - Classi parzialmente definite: Classi Astratte e Interfacce

Unità B2 Gestione eventi 2

Esempio su strutture dati dinamiche: ArrayList

Lezione n.10 LPR. RMI CallBacks

Esercitazione sui Design Pattern

Gerarchia delle classi Classi astratte Interfacce (Eccezioni) Laboratorio di Programmazione - Esercitazio 1

Programmazione. Cognome... Nome... Matricola... Prova scritta del 11 luglio 2014

oggetti, permettono di ridurre i costi di sviluppo, poiché cercano di riusare insiemi di classi e di produrre sistemi più facili da evolvere.

Interfacce. Esempio: interfaccia I con una sola funzione g() public interface I {

Ingegneria del Software Model View Controller

Corso di Laurea in Ingegneria Informatica. Corso di Reti di Calcolatori A.A. 2009/2010

LETTURA DI DATI DA INPUT. Gli stream di byte consentono già di leggere dati (numeri di vario tipo), tramite la classe DataInputStream

Eccezioni e Thread (cenni)

Sul pattern Iterator

Programmazione. Cognome... Nome... Matricola... Prova scritta del 22 settembre Negli esercizi proposti si utilizzano le seguenti classi:

Programmazione a oggetti

Note ed esercizi aggiuntivi

Lezione 5 Namespace e JavaDoc

Laboratorio di Sistemi Polimorfismo Java. Prerequisiti: per la comprensione dell'articolo è necessario conoscere il concetto di Ereditarietà in Java.

Ereditarietà. Linguaggi di Programmazione: Paradigmi di Programmazione. Ereditarietà. Sottoclassi. Ereditarietà. Controllo statico dei tipi

La Riflessione in Java

Esercizi su Callback RMI

Risoluzione dei metodi

Programmazione. Cognome... Nome... Matricola... Prova scritta del 20 febbraio 2012

Ereditarietà (ultima)

Ereditarietà (ultima)

STRUTTURE DATI: OLTRE GLI ARRAY LISTE

Riassunto. GUI in Java con l AWT 1. Cos è una GUI. Oggi: GUI in Java, l AWT. GUI in Java. Un esempio. Stefano Mizzaro 1

Ereditarietà: concetti di base

18 - Vettori. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Programmazione orientata agli oggetti Classi astratte e interfacce. Classi astratte - Interfacce

Preparazione allo scritto di Programmazione Comunicazione Digitale / Informatica - A.A. 2012/2013

Programmazione in Java e gestione della grafica. Lezione 21

Programmazione orientata agli oggetti Classi astratte e interfacce. Classi astratte - Interfacce

Programmazione Java Avanzata PATTERN

Esercizi su Java RMI. Progetto di Cliente / Servitore e supporto. Possibile tabella mantenuta dal server

Campo Minato. in java

Programmazione orientata agli oggetti Classi astratte e interfacce

Classi astratte e progettazione OOP Esempio: l enciclopedia degli animali

Informatica Ereditarietà Java. Ereditarietà

{4, 4, 2, 9, 13} {2, 2, 9, 13, 0} {0, 4, 2, 9, 13} {2, 9, 13, 0, 0}

Sul pattern Observer

A. Lorenzi, A. Rizzi Java. Programmazione ad oggetti e applicazioni Android Istituto Italiano Edizioni Atlas

Ereditarietà. Ereditarietà. Ereditarietà. Ereditarietà

Esonero del corso di Programmazione a Oggetti

I Thread. un thread è uno stream di esecuzione del programma

FileHandler. +getcontent():string +getline(number:int):string

Prova d Esame Compito A

SOMMARIO Tipo di dato astratto (ADT) : Interfacce: interface. TIPI DI DATI ASTRATTI. Polimorfismo: Tipo class. Tipo interface. Tipi run-time: is e as.

Polimorfismo parametrico vs polimorfismo per inclusione

LA CLASSE Data ESERCIZIO. Definiamo la classe Data che incapsuli giorno, mese e anno (tutti int)

Esercizio. Strutture Dati

Un approccio possibile sarebbe creare un oggetto con un metodo adeguato per scandire collezioni o stampare i dati dell oggetto:

Programmazione. Cognome... Nome... Matricola... Compitino del 17 gennaio 2007

Laboratorio di Sistemi Ordinamento di oggetti Java

Programmazione Java Avanzata Programmazione Object- Oriented in Java

Corso di Reti di Calcolatori T

Collezioni, mappe e iteratori (a cura del Prof. Marco Patella)

Lab 4: Design Patterns

Programmazione a Oggetti Metodologie di Programmazione 14 Maggio 2012

Il pattern FACTORY è un pattern di tipo Creazionale secondo la classificazione della GoF I pattern di tipo creazionali si occupano della costruzione

Interfacce. Un interfaccia Java è una collezione di metodi astratti (e di costanti) Un metodo astratto è un metodo non implementato

Classi astratte e progettazione OOP Esempio: l enciclopedia degli animali. Esempio Animali

Uguaglianza e copia di oggetti

Multithreading/2. Più richieste servite simultaneamente > 1 thread per ogni connessione client (+ 1 thread per accettare nuove richieste).

Programmazione ad Oggetti. Java Parte II

Esercitazione 2: Java Thread

Transcript:

Pattern Observer

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

Meccanismo del pattern Observer 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).

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

Struttura del pattern Observer

Partecipanti Interfaccia 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.

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

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 something setchanged(); notifyobservers("processo concluso"); Gli Observer sono conservati con un Vector

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.

Metodi di Subject void 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.

Come avviene la registrazione degli observer: Osservatore obs = new Osservatore(); Subject subject = new Subject(); subject.addobserver(obs); subject.startprocess();

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

Svantaggi Possibile 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

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

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

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 download 4)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.

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.

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);

//== Metodo download l'attività del subject public 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

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");

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");

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

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

Esempio: Observed Employee Supponiamo di dover realizzare in Observer che deve essere informato degli aumenti di stipendio di un impiegato 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);

Creiamo una sottoclasse di Employee che possiede un oggetto Observable, cui deleghiamo il meccanismo di notifica 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));

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. Soluzione Creare una classe DelegateObservable e fare l'ovverride dei metodi protected modificando la loro visibilità a public

class DelegatedObservable extends Observable { public void clearchanged() { super.clearchanged(); public void setchanged() { super.setchanged(); //== use del delegateobservable class 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!");

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);

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

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

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 ActionListener AdjustmentListener ItemListener TextListener MouseMotionListener WindowListener ComponentListener ContainerListener FocusListener KeyListener MouseListener

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)