Programmazione con Interfacce

Slides:



Advertisements
Presentazioni simili
Programmazione ad oggetti
Advertisements

Classi ed Oggetti in JAVA
Oggetti Java.
Costruttori e Distruttori
Recupero debito quarto anno Primo incontro
Informatica 2 Lezione 4 Corso di laurea in matematica Informatica 2 Dott. Ing. Leonardo Vito Corso di laurea matematica indirizzo matematica per le applicazioni.
9/11/2004Laboratorio di Programmazione - Luca Tesei1 Tipi numerici di base - Costanti Interi e decimali Definizione di costanti.
29/11/2004Laboratorio di Programmazione - Luca Tesei1 Ancora sulla progettazione/Pacchetti Concetti di coesione/accoppiamento/coerenza Uso dei package.
Programmazione object oriented in C++
Capitolo 8 Array Lucidi relativi al volume: Java – Guida alla programmazione James Cohoon, Jack Davidson Copyright © The McGraw-Hill Companies srl.
Differenze nei vari linguaggi di Elisa Trifirò e Barbara Tacchino
Massa Laura Mela Enrica
1 Astrazioni sui dati : Specifica ed Implementazione di Tipi di Dato Astratti in Java.
1 Semantica Operazionale di un frammento di Java: lo stato.
Classi ed Oggetti in Java (Cenni). Richiami Ruolo delle Classi in Java Oggetti.
Le gerarchie di tipi.
Liste Ordinate 3 Maggio Ultima Lezione Abbiamo visto i tipi di dato astratti IntList e StringList Realizzano liste di interi e di stringhe Realizzati.
LIP: 1 Marzo 2005 Classe Object e Vettori. Partiamo da Lesercizio dellultima esercitazione realizzato tramite array Vedremo come si puo fare in modo piu.
Interfacce. Interfacce come strumento di progetto Scelta delle classi di un progetto Criteri di coesione e accoppiamento Interfacce e riuso di codice.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Puntatori Marco D. Santambrogio – Ver. aggiornata al 21 Marzo 2013.
1 Programmazione ad oggetti in Java E.Mumolo, DEEI
1 Corso di Laurea in Biotecnologie Informatica (Programmazione) Introduzione a JAVA Anno Accademico 2009/2010.
Corso di Laurea in Biotecnologie Informatica (Programmazione)
Corso di Informatica (Programmazione)
1 Corso di Informatica (Programmazione) Lezione 13 (21 novembre 2008) Programmazione in Java: stringhe e array.
1 Lezione XIII Lu 17-Nov-2005 Programmare le classi.
Overriding.
Soluzione Esercizio - Classe Vettore
Gestione dei Progetti Software 2 (a.a. 2004/05) - Lezione 3 1 JAVA e Internet: il World Wide Web Internet: milioni di computer collegati fra di loro attraverso.
Istruzioni di selezione in Java Programmazione Corso di laurea in Informatica.
Approfondimento delle classi
Ereditarietà. Concetti principali Ereditarietà e (overriding) di metodi Dynamic dispatch e polimorfismo Ereditarietà e costruttori Livelli di accesso.
Ereditarietà. Concetti principali Ereditarietà e (overriding) di metodi Dynamic dispatch e polimorfismo Ereditarietà e costruttori Livelli di accesso.
Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.
Progetto di applicazioni grafiche. Disegno di forme complesse Prassi : un classe per ciascuna forma Progetta la forma individuando le componenti base.
Classi. Progetto di classi: Dalla specifica dellinterfaccia, alla definizione dellimplementazione Metodi Costruttori Documentazione e commenti Variabili.
Capitolo 9 Interfacce e polimorfismo
Capitolo 3 Realizzare classi
Capitolo 4 Tipi di dati fondamentali
Le classi Definizione di classe Attributi e metodi di una classe Costruttori e distruttori Private e public Funzioni friend Il puntatore this.
Strutture di controllo in C -- Flow Chart --
Le funzioni.
Java base IV: Java e la programmazione O.O.
Elementi di programmazione ad oggetti a. a. 2009/2010 Corso di Laurea Magistrale in Ingegneria Elettronica Docente: Mauro Mazzieri, Dipartimento di Ingegneria.
Java Contardi Carlo A.S. 2008/09.
Scheda Ente Ente Privato Ente Pubblico. 2ROL - Richieste On Line.
2000 Prentice Hall, Inc. All rights reserved. Capitolo 10 (Deitel) Strutture, unioni ed enumerazioni Sommario Introduzione Definire le strutture.
ISTITUTO STATALE DI ISTRUZIONE SUPERIORE F. ENRIQUES CORSO JAVA – PROVA INTERMEDIA DEL 12 MARZO 2007 NOME: COGNOME: ________________________________________________________________________________.
1 Questionario di soddisfazione ATA - a. sc. 2008/09 Il questionario è stato somministrato nel mese di aprile Sono stati restituiti 29 questionari.
Enumerazioni e Classi 1. Enumerazioni Permettono di definire nuovi tipi che consistono in un insieme di valori costanti (ognuno con un nome) – Migliorano.
1 Lucidi delle esercitazioni di Sistemi di Elaborazione in Rete Università degli Studi della Calabria Corso di Laurea in Ingegneria Gestionale A.A. 2003/2004.
Fopndamenti di programmazione. 2 La classe String Una stringa è una sequenza di caratteri La classe String è utilizzata per memorizzare caratteri La classe.
Fondamenti di Programmazione Prof.ssa Elisa Tiezzi
Bando di Residenza Cap Scheda ENTE 3ROL - Richieste On Line.
1Piero Scotto - C14. Finalità del corso Programma Materiale Requisiti Spendibilità 2Piero Scotto - C14.
Sviluppare un programma in C che, dato un array da 100 elementi interi caricato con numeri casuali compresi tra [10,100], sia in grado di cercare il valore.
ISTITUTO STATALE DI ISTRUZIONE SUPERIORE F. ENRIQUES CORSO JAVA – PROVA INTERMEDIA DEL 12 MARZO 2007 NOME: COGNOME: ________________________________________________________________________________.
I nomi in Java F. Bombi 18 novembre novembre 2003.
1 FONDAMENTI DI INFORMATICA II Ingegneria Gestionale a.a ° Ciclo Approfondimenti sulle Classi.
Il linguaggio Fortran 90: 3. Procedure e Funzioni
Programmazione ad oggetti
30/11/2004Laboratorio di Programmazione - Luca Tesei1 Interfacce e Polimorfismo.
Ereditarieta’. Contenuti Introduciamo un meccanismo fondamentale di Java: l’ereditarieta’ Permette di estendere classi gia’ definite (ovvero di definire.
Esercitazione su Vector. Permette di definire collezioni di dati generiche, che sono in grado di memorizzare elementi di ogni sottotipo di Object Definito.
Progettare una classe 21 Febbraio La classe BankAccount Vogliamo realizzare una classe i cui oggetti sono dei semplici conti bancari. * Identifichiamo.
Classi ed Oggetti in Java (Cenni). Richiami Cenni sull’ Implementazione, Macchine Astratte, Compilatore, Interprete Ruolo delle Classi in Java Oggetti.
Ese 1 e 3 (del 6 Aprile 2005). Primo Ese Si identifichino gli errori che il compilatore segnalerebbe per il seguente programma Tipi Legami tra dichiarazioni.
Fondamenti di informatica T-A Esercitazione 3 : Classi, metodi, visibilità, metodi statici AA 2012/2013 Tutor : Domenico Di Carlo.
Introduzione all’Ereditarietà Pietro Palladino. Richiami UML Classe: descrizione di un insieme di oggetti software con caratteristiche simili Definisce.
Introduzione alle Classi e agli Oggetti in Java 1.
Transcript della presentazione:

Programmazione con Interfacce

Scelta delle classi di un progetto Interfacce Criteri di coesione e accoppiamento Interfacce Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch Interfacce come strumento di progetto Interfacce e riuso di codice Callbacks Classi interne

Organizzazione di una classe public class ClassTemplate { // costanti pubbliche // costruttori pubblici // metodi “accessors” pubblici // metodi “mutators” pubblici // campi privati // classi interne e metodi ausiliari privati } Continua…

Organizzazione di una classe Visibilità dei campi: evitare campi pubblici Quando necessario, definite metodi per accedere e modificare i campi Completezza dell’interfaccia pubblica Assicuratevi che l’interfaccia pubblica fornisca le funzionalità necessarie per un utilizzo naturale ed efficace delle istanze Documentate il codice Non solo commenti (vedremo …)

Classi di un progetto Una classe dovrebbe rappresentare un concetto singolo, oppure un insieme di valori ben caratterizzato (un tipo) Concetti/tipi in matematica: Point, Rectangle, ..., Set, List, ... Concetti/tipi nella vita reale BankAccount, CashRegister, ... Continua…

Classi di un progetto Una classe può anche identificare un insieme di “attori” oggetti che offrono un insieme di funzionalità Scanner, RandomNumberGenerator Una classe può anche agire da contenitore di metodi e campi static (quindi una classe senza istanze) Math inizializzatore della computazione (mediante il main)

Coesione Una classe dovrebbe rappresentare un solo concetto L’interfaccia pubblica di una classe è coesa se tutte le sue componenti sono relative al concetto che la classe rappresenta Continua…

Coesione Questo è un esempio di classe non coesa … Perché? public class CashRegister { public void enterPayment(int dollars, int quarters, int dimes, int nickels, int pennies) . . . public static final double NICKEL_VALUE = 0.05; public static final double DIME_VALUE = 0.1; public static final double QUARTER_VALUE = 0.25; . . . } Continua…

Coesione CashRegister coinvolge due concetti: Registratore di cassa, monete Soluzione alternativa: due classi public class Coin { public Coin(double aValue, String aName){ . . . } public String getName(){ . . . } . . . } public class CashRegister { public void enterPayment(Coin... coins) { . . . } . . . } vararg

Accoppiamento (Coupling ) Una classe dipende da un’altra classe se utilizza oggetti di quella classe CashRegister dipende da Coin per il calcolo della somma del pagamento Coin non dipende CashRegister Continua…

UML Per visualizzare le relazioni tra classi utilizziamo diagrammi UML: Unified Modeling Language. Notazione standard per l’analisi ed il progetto di applicazioni software

Gradi di accoppiamento Alto grado di accoppiamento implica molte dipendenze tra classi Basso grado di accoppiamenento facilita manutenibilità in caso di modifica delle componenti (della loro interfaccia esterna) Continua…

Gradi di accoppiamento Vedremo tecniche per bilanciare correttamente il grado di accoppiamento

Interfacce L’impiego di tipi interfaccia nel progetto di una applicazione rende il codice flessibile e robusto favorisce il riuso di codice permette di controllare il grado di accoppiamento tra le componenti del progetto Esempio: definiamo una classe DataSet che permette di condurre alcune semplici analisi su un insieme di dati numerici calcolo della media calcolo del valore massimo Continua…

DataSet public class DataSet { public void add(double x) { sum = sum + x; if (count == 0 || maximum < x) maximum = x; count++; } public double getMaximum(){ return maximum; } public double average() { return (count>0)? sum/count : Double.NaN; } private double sum; private double maximum; private int count; }

Interfacce Ora supponiamo di voler condurre le stesse analisi su un insieme di conti bancari per tracciare la media degli importi del saldo calcolare il conto con il saldo massimo. monete per calcolare l taglio medio delle monete determinare il taglio massimo La struttura della classe è sempre la stessa, ma il codice cambia … Continua…

DataSet – versione per BankAccount public class DataSet { public void add(BankAccount x) { sum = sum + x.getBalance(); if (count == 0 || maximum.getBalance() < x.getBalance()) maximum = x; count++; } public BankAccount getMaximum() { return maximum; } public double average() {return (count>0)? sum/count : Double.NaN; } private double sum; private BankAccount maximum; private int count; }

DataSet – versione per Coin public class DataSet { public void add(Coin x) { sum = sum + x.getValue(); if (count == 0 || maximum.getValue() < x.getValue()) maximum = x; count++; } public Coin getMaximum() { return maximum; } public double average() {return (count>0)? sum/count : Double.NaN; } private double sum; private Coin maximum; private int count; }

Interfacce riuso di codice Il meccanismo di analisi dei dati è sempre lo stesso; la differenza è solo nel metodo che estrae i valori E se le diverse classi si uniformassero nell’uso di uno stesso metodo, getMeasure() per fornire la misura? In quel caso potremmo definire una sola versione di DataSet con un metodo add() come il seguente sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure()) maximum = x; count++; Continua… Continua…

Interfacce riuso di codice Quale è il tipo della variabile x a questo punto? Idea: il tipo di una qualunque classe che fornisca un metodo getMeasure In Java usiamo tipi interfaccia Una dichiarazione di interfaccia include tutti i metodi (le loro firme) che intendiamo attribuire al tipo interfaccia corrispondente public interface Measurable { double getMeasure(); }

DataSet – versione generica public class DataSet { public void add(Measurable x) { sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure()) maximum = x; count++; } public Measurable getMaximum() { return maximum; } public double average() { return sum/count; } private double sum; private Measurable maximum; private int count; }

Classi vs. Interfacce Un tipo interfaccia è simile ad un tipo classe, ma ci sono molte differenze importanti: I metodi (tutti) dell’interfaccia sono “astratti” L’interfaccia non definisce una implementazione Tutti i metodi di una interfaccia sono automaticamente pubblici Una interfaccia non ha campi (mentre può avere campi statici, ovvero costanti)

Classi implementano Interfacce La keyword implements indica che una classe implementa una interfaccia Una classe può implementare più interfacce La classe deve implementare tutti i metodi di tutte le interfacce che implementa tutti questi metodi devono essere public nella classe public class BankAccount implements Measurable { public double getMeasure() { return balance; } // altri metodi, campi e quant’altro ... } Continua…

Classi implementano Interfacce Measurable Coins public class Coin implements Measurable { public double getMeasure() { return value; } // . . . }

Diagrammi UML Notazione: Le interfacce sono rappresentate utilizzando la tag «interface» associata al nome oppure indicando il nome in corsivo La relazione tra una interfaccia ed una classe che la implementa è rappresentata da una freccia tratteggiaga (dalla classe all’interfaccia) Notazione simile alla dipendenza: cambia la punta della freccia Continua…

Diagramma UML per l’esempio implementa dipende

Diagrammi UML L’impiego di interfacce riduce il numero di classi ed il grado di accoppiamento tra le classi Notate infatti che DataSet è disaccoppiata da BankAccount e Coin Possiamo liberamente modificare le classi basta che implementino correttamente l’interfaccia

Sintassi: definizione di interfaccia public interface InterfaceName { // firme e contratti per i metodi } Esempio:  public interface Measurable { double getMeasure(); } Scopo: Definire le firme ed i contratti per i metodi di un tipo interfaccia. Tutti i metodi sono automaticamente pubblici.

Sintassi: dichiarazione di classe  public class ClassName implements InterfaceName, InterfaceName, ... { // ... } Eesmpio:  public class BankAccount implements Measurable //... public double getMeasure() // Method implementation } Scopo: Fornire una implementazione per il tipo interfaccia

File DataSetTester.java 01: /** 02: This program tests the DataSet class. 03: */ 04: public class DataSetTester 05: { 06: public static void main(String[] args) 07: { 08: DataSet bankData = new DataSet(); 09: 10: bankData.add(new BankAccount(0)); 11: bankData.add(new BankAccount(10000)); 12: bankData.add(new BankAccount(2000)); 13: 14: System.out.println("Average balance = " 15: + bankData.getAverage()); 16: Measurable max = bankData.getMaximum(); 17: System.out.println("Highest balance = " 18: + max.getMeasure()); Continua…

File DataSetTester.java 19: 20: DataSet coinData = new DataSet(); 21: 22: coinData.add(new Coin(0.25, "quarter")); 23: coinData.add(new Coin(0.1, "dime")); 24: coinData.add(new Coin(0.05, "nickel")); 25: 26: System.out.println("Average coin value = " 27: + coinData.getAverage()); 28: max = coinData.getMaximum(); 29: System.out.println("Highest coin value = " 30: + max.getMeasure()); 31: } 32: } Continua…

File DataSetTester.java Output: Average balance = 4000.0 Highest balance = 10000.0 Average coin value = 0.13333333333333333 Highest coin value = 0.25

Domanda Vogliamo utilizzare la classe DataSet per trovare l’istanza di una classe Country con la popolazione maggiore in un insieme. Quali condizioni deve soddisfare la classe Country?

Domanda Cosa c’è di sbagliato nel seguente codice? public void add(Object x) { sum = sum + x.getMeasure(); if (count == 0 || maximum.getMeasure() < x.getMeasure()) maximum = x; count++; }

Risposta Deve implementare l’interfaccia Measurable ed il suo metodo getMeasure() deve restituire il valore della popolazione

Risposta La classe Object non ha un metodo getMeasure(), che viene invocato all’interno del metodo add()

Conversioni di tipo Variabile: locazione con un tipo associato Tipo della variabile determinato dal compilatore guardando la dichiarazione Una variabile di tipo reference contiene un riferimento ad un oggetto Oggetto: istanza di una classe Tipo dell’oggetto: la classe che lo crea Determinato a run time Una variabile può assumere come valori riferimenti ad oggetti di classi diverse Continua…

Conversioni di tipo È possibile assegnare un riferimento di tipo classe ad una variabile di tipo interfaccia purchè la classe implementi l’interfaccia BankAccount account = new BankAccount(10000); Measurable x = account; // OK Coin dime = new Coin(0.1, "dime"); Measurable y = dime; // OK Continua…

Conversioni di tipo La conversione è lecita solo in determinate situazioni Problema: Rectangle non implementa Measurable Measurable x = new Rectangle(5, 10, 20, 30); // ERRORE

Subtyping Subtyping (<:) Chi decide cosa/quando è legittimo? Una relazione che permette di decidere quando è legittimo convertire un tipo riferimento in un altro Chi decide cosa/quando è legittimo? il compilatore! Per il momento la regola è: T1 <: T2 sse T1 è una classe, T2 è una interfaccia T1 implementa T2. Continua…

Subtyping Principio di sostituibilità Un riferimento di un sottotipo può essere usato ovunque ci si aspetti un riferimento di un supertipo Le regole di sottotipo devono garantire la correttezza del principio di sostituibilità Continua…

Subtyping La regola Principio di sostituibilità E’ ragionevole perché C <: I se C implementa I Principio di sostituibilità un riferimento di tipo C può sempre essere usato dove si attende un riferimento di tipo I E’ ragionevole perché se C implementa I , C definisce public tutti i metodi dichiarati da I Quindi tutti le invocazioni di metodo possibili per I sono supportate da C Continua…

Subtyping e regole di typing Regola di assegnamento Un riferimento di tipo T1 si puo sempre assegnare ad una variabile di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere assegnato ad una variabile di tipo interfaccia (se la classe implementa l’interfaccia) Regola di passaggio di parametri Un riferimento di tipo T1 si puo sempre passare per un parametro di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere passato per un parametro di tipo interfaccia (se la classe implementa l’interfaccia)

Domanda Data l’implementazione generica della classe DataSet, che oggetti possiamo passare come argomento per x ? public class DataSet { public void add(Measurable x) { ... } ... }

Risposta Qualunque istanza di una una classe che implementa Measurable

Cast Consideriamo Cosa possiamo fare con max? Certamente non sapere quale moneta è … DataSet coinDS = new DataSet(); coinDS.add(new Coin(0.25, "quarter")); coinDS.add(new Coin(0.1, "dime")); . . . Measurable max = coinDS.getMaximum(); String name = max.getName(); // ERRORE: Non ha tipo Coin Continua…

Cast Measurable max = coinDS.getMaximum(); Noi sappiamo che max è un riferimento di tipo Coin, ma il compilatore no. Dobbiamo usare un cast per convertire il tipo interfaccia nel tipo classe Ora usiamo maxCoin come desiderato Coin maxCoin = (Coin) max; String name = maxCoin.getName(); Continua…

Cast Un cast è permesso dal compilatore solo se applica conversioni tra tipi compatibili Compatibili = sottotipi (per il momento) Anche quando permesso dal compilatore, un cast può causare errore a run time Se max non è un Coin errore a run time Coin maxCoin = (Coin) max; Continua…

Cast Tipo statico e tipo dinamico di una variabile (T)var causa errore tipo statico: quello dichiarato tipo dinamico: il tipo del riferimento assegnato alla variabile (T)var causa errore in compilazione se T non è compatibile con il tipo statico di var in esecuzione se T non è compatibile con il tipo dinamico di var Continua…

Cast OK: BankAccount sottotipo di Measurable Compila correttamente il tipo dichiarato di m è Measurable BankAccount e Measurable sono compatibili Esegue correttamente m è un BankAccount (il tipo dinamico di m è BankAccount) Measurable m = new BankAccount(); BankAccount b = (BankAccount) m Continua…

Cast OK: BankAccount sottotipo di Measurable Compila correttamente il tipo dichiarato di m è Measurable Coin e Measurable sono compatibili Errore a run time m non è un Coin Measurable m = new BankAccount(); Coin c = (Coin) m Continua…

instanceof Permette di determinare il tipo dinamico di una variabile Quindi permette di evitare errori in esecuzione Esegue correttamente, perchè x è sicuramente un T x istanceof T è true solo se x ha tipo dinamico T if (x instanceof T) return (T) x

Domanda Dato che sia BankAccount che Coin implementano l’interfaccia Measurable, è possibile convertire un riferimento di tipo Coin ad uno di tipo BankAccount?

Risposta No: un riferimento di tipo Coin può essere convertito a Measurable, ma se poi tentiamo di applicare un cast a BankAccount, abbiamo una eccezione.

Domanda E’ corretto un cast (BankAccount) x per convertire una variabile x di tipo dichiarato Measurable ad un riferimento di tipo BankAccount?

Risposta Solo se x contiene effettivamente un riferimento ad un oggetto di tipo BankAccount.

Polimorfismo – dynamic dispatch Una variabile di tipo interfaccia ha sempre come valore un riferimento di una classe che implementa l’interfaccia Measurable x; x = new BankAccount(10000); x = new Coin(0.1, "dime"); Continua…

Polimorfismo – dynamic dispatch Possiamo invocare ognuno dei metodi dell’interfaccia: Quale metodo invoca? double m = x.getMeasure();

Polimorfismo – dynamic dispatch Dipende dal riferimento corrente memorizzato nella variabile  Se x riferisce un BankAccount, invoca il metodo BankAccount.getMeasure() Se x riferisce un Coin, invoca il metodo Coin.getMeasure() Polimorfismo (molte forme): il comportamento varia, e dipende dal tipo dinamico della variabile Continua…

Polimorfismo – dynamic dispatch Detto anche late binding: deciso a tempo di esecuzione Diverso dal caso dell’overloading: Anche nel caso dell’overloading si deve decidere quale versione del metodo invocare Ma qui la decisione viene risolta in compilazione (early binding)

Domande È impossibile costruire un oggetto di tipo Measurable.Perché? Perché invece é possibile dichiarare una variabile di tipo Measurable?

Risposte Measurable è una interfaccia. Le interfacce non hanno campi o implementazione di metodo. Perché Measurable è un tipo: la variabile non riferirà mai una istanza di Measurable, (le interfacce non hanno istanze) ma piuttosto oggetto di una qualche classe che implementa l’interfaccia Measurable. Continua…

Domanda Che cosa hanno in comune i meccanismi di overloading e di dynamic dispatch? In cosa sono diversi?

Risposte Entrambi i meccanismi decidono quale metodo eseguire in risposta ad un messaggio, ma Nell’overloading la scelta è fatta in compilazione guardando il tipo dei parametri Nel dynamic dispatch la scelta è fatta in esecuzione guardando il tipo dell’oggetto che riceve il messaggio

Esempio Costruiamo una applicazione per disegnare un insieme di forme geometriche contenute in una componente grafico: definiamo una JComponent contenitore per un insieme di forme geometriche disegnate mediante una invocazione del metodo paintComponent() per esemplificare, consideriamo due tipi di forme: Car e Smiley

Forme grafiche class Car { . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . } } class Smiley { . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . } }

ShapeComponent Un contenitore di Cars e Smileys Un caso particolare di JComponent /** Una component che contiene un insieme Cars e Smileys */ class ShapeComponent extends JComponent { Disegna tutte le forme di questo component public void paintComponent(Graphics g){ /* ... */ } }

Domanda Che struttura utilizziamo per memorizzare le forme contenute nella ShapeComponent? Come definiamo il metodo paintComponent() in modo che disegni tutte le forme della componente?

interface Shape { void draw(Graphics2D g); } Risposte ArrayList: definiamo una nuova interfaccia: Shape Ridefiniamo le classi Car e Smiley in modo che implementino Shape Memorizziamo gli oggetti della componente in una ArrayList<Shape> interface Shape { void draw(Graphics2D g); }

Car e Smiley implementano Shape class Car implements Shape { . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . } } class Smiley implements Shape { . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . } }

ShapeComponent Mantiene una ArrayList<Shape> // Una component che contiene un insieme forme class ShapeComponent extends JComponent { private ArrayList<Shape> shapes; // crea una componente con un insieme di forme public ShapeComponent(Shape... shapes) { this.shapes = new ArrayList<Shape>(); for (Shape s:shapes) this.shapes.add(s); } // disegna tutte le componenti della componente public void paintComponent(Graphics2D g2){ for (Shape c:shapes) c.draw(g2);

Diagramma delle Classi Car ShapeComponent Smiley Shape

Domanda E se volessimo disegnare solo le Shapes che sono Cars?

Risposta // disegna tutte le cars della componente public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D) g; for (Shape c:shapes) if (c instanceof Car) c.draw(g2); }

Interfacce e “callbacks” La tecnica che abbiamo visto funziona per classi di cui abbiamo il controllo Nel caso delle forme geometrice, possiamo rendere Car e Smiley implementazioni di Shape Nel caso del DataSet rendiamo Measurable le classi Coin e BankAccount Che facciamo se non possiamo modificare la definizione delle classi? Continua…

Interfacce e “callbacks” Esempio: Vogliamo misurare l’area media e l’area massima di un insieme di Rectangles Rectangle è una classe predefinita, e non implementa Measurable … Continua…

Interfacce e “callbacks” Callback: tradizionalmente (*) indica un meccanismo per passare ad una funzione un’altra funzione che esegue una qualche operazione specifica La funziona passata come argomento si definisce callback (*) almeno dai tempi del progetto MIT che diede luogo a X (meglio noto com X11) … correva l’anno 1984 Continua…

Interfacce e “callbacks” Esempio classico: una funzione che gestisce le scelte di un menù definita in termini di un parametro di tipo funzione che viene invocata per gestire l’operazione da eseguire in risposta alla selezione degli items del menù Il parametro è una callback Continua…

Interfacce e “callbacks” Nei linguaggi ad oggetti non possiamo passare parametri di tipo funzione In C# esiste un costrutto predefinito che realizza questo meccanismo: i delegates In Java il meccanismo può essere simulato definiamo una classe con un metodo che implementa la funzione callback passiamo un oggetto di quella classe e lo utilizziamo per invocare la callback

Callbacks per DataSet Problema: misurare l’area media e l’area massima di un insieme di Rectangles Nell’implementazione vista, gli oggetti da misurare offrono direttamente il metodo che misura Alternativa: passiamo alla classe DataSet un metodo per misurare oggetti Continua…

Callbacks per DataSet measure() misura qualunque oggetto e Measurer rappresenta qualunque classe lo definisca Object è il supertipo di tutti i tipi riferimento qualunque riferimento si può passare per un parametro di tipo Object public interface Measurer { double measure(Object anObject); } Continua…

Callbacks per DataSet La classe DataSet diventa dipendente dal metodo di misura, ovvero da qualunque classe che definisca questo metodo public class DataSet { ... public DataSet(Measurer aMeasurer) { measurer = aMeasurer; } ... private Measurer measurer; Continua…

Callbacks per DataSet Ora il metodo add() richiede la misura al measurer non all’oggetto che viene incluso nel dataset. public void add(Object x) { sum = sum + measurer.measure(x); if (count == 0 || measurer.measure(maximum) < measurer.measure(x)) maximum = x; count++; } Continua…

Callbacks per DataSet Possiamo definire Measurers per qualunque tipo di misura, in particolare per misurare Rectangles public class RectangleMeasurer implements Measurer { public double measure(Object anObject) { if (!anObject instanceof Rectangle) return Double.NaN; Rectangle aRectangle = (Rectangle) anObject; double area = aRectangle.getWidth() * aRectangle.getHeight(); return area; } } Continua…

Callbacks per DataSet Notiamo il cast da Object a Rectangle Passiamo il measurer desiderato al momento della costruzione del dataset Dynamic dispatch => invochiamo l’implementazione di measure() fornita da RectangleMeasurer Rectangle aRectangle = (Rectangle) anObject; Measurer m = new RectangleMeasurer(); DataSet data = new DataSet(m); data.add(new Rectangle(5, 10, 20, 30)); . . . Continua…

Diagramma delle classi Notate che la classe Rectangle è disaccoppiata dall’interfaccia Measurer double measure(Object o)

Raffronto tra le due soluzioni Callbacks Measurer double measure(Object o) Oggetti Measurable Rectangle double getMeasure()

File DataSet.java 01: /** 02: Calcola la media di un insieme di oggetti. 03: */ 04: public class DataSet 05: { 06: /** 07: Costruisce un insieme vuoto con un dato misuratore. 08: @param aMeasurer il misuratore utilizzato per misurare i valori 09: */ 10: public DataSet(Measurer aMeasurer) 11: { 12: sum = 0; 13: count = 0; 14: maximum = null; 15: measurer = aMeasurer; 16: } 17: Continua…

File DataSet.java 18: /** 19: aggiunge un valore al dataset. 18: /** 19: aggiunge un valore al dataset. 20: @param x un dato 21: */ 22: public void add(Object x) 23: { 24: sum = sum + measurer.measure(x); 25: if (count == 0 26: || measurer.measure(maximum) < measurer.measure(x)) 27: maximum = x; 28: count++; 29: } 30: 31: /** 32: Calcola la media dei dati considerati. 33: @return la media o 0 se l’insieme di dati è vuoto 34: */ Continued…

File DataSet.java 35: public double average() 36: { 36: { 37: if (count == 0) return 0; 38: else return sum / count; 39: } 40: 41: /** 42: Il massimo del dataset. 43: @return il massimo o 0 se non il dataset è vuoto 44: */ 45: public Object maximum() 46: { 47: return maximum; 48: } 49: Continua…

File DataSet.java 50: private double sum; 51: private Object maximum; 52: private int count; 53: private Measurer measurer; 54: }

File DataSetTester.java 01: import java.awt.Rectangle; 02: 03: /** 04: Dimostra l’uso del misuratore. 05: */ 06: public class DataSetTester 07: { 08: public static void main(String[] args) 09: { 10: Measurer m = new RectangleMeasurer(); 11: 12: DataSet data = new DataSet(m); 13: 14: data.add(new Rectangle(5, 10, 20, 30)); 15: data.add(new Rectangle(10, 20, 30, 40)); 16: data.add(new Rectangle(20, 30, 5, 10)); 17: Continua…

File DataSetTester.java 18: System.out.println("Average area = " + data.getAverage()); 19: Rectangle max = (Rectangle) data.getMaximum(); 20: System.out.println("Maximum area rectangle = " + max); 21: } 22: }

File Measurer.java 01: /** 02: Interfaccia di qualunque classe le cui istanze misurano altri oggetti. 03: */ 04: public interface Measurer 05: { 06: /** 07: Calcola la misura di un oggetto. 08: @param anObject l’oggetto da misurare 09: @return la misura 10: */ 11: double measure(Object anObject); 12: }

File RectangleMeasurer.java 01: import java.awt.Rectangle; 02: 03: /** 04: le istanze di questa classe misurano l’area di un rettangolo 05: */ 06: public class RectangleMeasurer implements Measurer 07: { 08: public double measure(Object anObject) 09: { 10: Rectangle aRectangle = (Rectangle) anObject; 11: double area = aRectangle.getWidth() * aRectangle.getHeight(); 12: return area; 13: } 14: } 15: Continua…

File RectangleMeasurer.java Output: Average area = 616.6666666666666 Maximum area rectangle = java.awt.Rectangle[x=10,y=20, width=30,height=40]

Domanda Supponiamo di voler utilizzare la prima versione della classe DataSet per trovare la Stringa più lunga di un insieme dato in input. Quale è il problema?

Risposta Problema: la classe String non implementa Measurable.

Domanda Come possiamo utilizzare la seconda versione di DataSet (con callbacks) per risolvere il problema precedente?

Risposta Definendo una classe StringMeasurer che implementa l’interfaccia Measurer

Domanda Perchè il metoto measure() dell’interfaccia Measurer ha un parametro in più del metodo getMeasure() dell’interfaccia Measurable?

Risposta measure() misura un oggetto, passato come argomento, mentre getMeasure() misura this, ovvero il parametro implicito.

Esercizio Definiamo una nuova versione della classe DataSet che sia utilizzabile sia su oggetti generici, mediante un Measurer, sia su oggetti Measurable. Il comportamento del metodo add() dipende dal tipo dell’argomento: se il tipo è Measurable, l’argomento viene misurato utilizzando il suo metodo getMeasure() in tutti gli altri casi, viene misutato dal Measurer del data set

Callbacks nella gestione di un timer La classe javax.swing.Timer definisce oggetti che generano eventi (ticks) Utile tutte le volte che vogliamo modificare un oggetto ad intervalli di tempo regolari Ad esempio nelle animazioni: Smiley: modifica il saluto oppure l’espressione Car: si muove sul frame ad intervalli regolari Continua…

Gestione di un timer Eventi notificati ad un “Action Listener” associato al timer Action Listener descritto da una interfaccia standard (predefinita) actionPerformed() invocato ad ogni tick event: contiene informazione sull’evento public interface ActionListener {    void actionPerformed(ActionEvent event); } Continua…

Gestione di un timer La gestione dell’evento avviene nel metodo actionPerformed() Gestioni diverse realizzate da classi diverse che implementano ActionListener class MyListener implements ActionListener {      public void actionPerformed(ActionEvent event)     {       // Eseguito ad ogni tick.     } } Continua…

Gestione di un timer Per associare un particolare listener al timer è necessario registrare il listener sul timer Ora possiamo far partire il timer MyListener listener = new MyListener(); Timer t = new Timer(interval, listener); tra due tick t.start(); // Esegue in un thread separato

Domanda Quale è il ruolo del listener nel timer?

Risposta Il listener implementa una callback: il metodo actionPerformed() è la vera callback che viene inclusa nel listener per poter essere passata al controllore del timer che la invoca ad ogni tick

Esempio: conto alla rovescia Un timer che esegue il countdown

File CountDown.java class CountDown implements ActionListener { public CountDown(int initialCount) count = initialCount; } public void actionPerformed(ActionEvent event){} public void actionPerformed() if (count >= 0) System.out.println(count); if (count == 0) System.out.println("Liftoff!"); count--; private int count; Continua…

File TimeTester.java import java.awt.event.*; import javax.swing.*; /** Esemplifica la classe timer l’uso di action listeners. */ public class TimeTester { public static void main(String[] args) CountDown listener = new CountDown(10); final int DELAY = 1000;// Millisecondi tra due tick Timer t = new Timer(DELAY, listener); t.start(); JOptionPane.showMessageDialog(null, "Quit?"); System.exit(0); }

Domanda Quante volte viene chiamato il metodo actionPerformed nel programma precedente?

Risposta Il metodo viene invocato una volta al secondo. Le prime 11 volte scrive un messaggio. Le successive termina senza output, decrementando il contatore. Il timer termina quando l’utente chiude l’applicazione

NOTE Tutti gli eventi del timer vengono gestiti dallo stesso thread (l’Event Dispatch Thread) se la gestione dell’evento richiede più tempo dell’intervallo, gli eventi vengono persi Informazione sull’utilizzo di timers in swing: http://java.sun.com.j2se/1.5.0/docs/api/javax/swing/Timer.html

Packages Package: insieme di classi e interfacce in relazione Per formare un package basta inserire la direttiva come prima istruzione nel file sorgente Una sola direttiva per file Classi contenute in file che non dichiarano packages vengono incluse in un package “anonimo” package anonimo OK solo per micro applicazioni, o in fase di sviluppo package packageName; Continua…

Packages Package Finalità Classe Tipica java.lang Supporto al linguaggio Math, String java.util Utilities Random java.io Input e Output PrintStream Java.awt Abstract Window Toolkit Color Java.applet Applets Applet Java.net Networking Socket Java.sql Accesso a database ResultSet Java.swing Ingerfaccia utente Swing JButton …

Accesso agli elementi di un package Per accedere ai tipi di un package utilizziamo il nome “qualificato” Uso dei nomi qualificati verboso import permette sintesi java.util.Scanner in = new java.util.Scanner(System.in); import java.util.Scanner; . . . Scanner in = new Scanner(System.in)

Import di una classe di tutte le classi di un package import java.util.Scanner; . . . Scanner in = new Scanner(System.in) import java.util.*; Continua…

Import Packages non formano gerarchie Static import delle costanti e metodi statici dei tipi di un package // import dei tipi di java.awt.color import java.awt.color.*; // import dei tipi di java.awt (non del package color!) import java.awt.*;// import dei tipi di java.awt. import static java.lang.Math.PI import static java.lang.Math.*;.

Nomi di package Packages utili anche come “namespaces” per evitare conflitti di nomi (per classi/interfacce) Esempio, Java ha due classi Timer Nomi di package devono essere univoci Convenzione: utilizziamo come prefissi domini internet, oppure indirizzi e-mail (in ordine inverso) java.util.Timer vs. javax.swing.Timer it.unive.dsi it.unive.dsi.mp Continua…

Localizzazione di package Nomi di package devono essere consistenti con i path della directory che li contengono Deve essere contenuto in un folder/directory localizzato nel path corrispondente it.unive.dsi.mp.banking UNIX: <base directory>/it/unive/dsi/mp/banking WINDOWS: <base directory>\it\unive\dsi\mp\banking Continua…

Localizzazione di package CLASSPATH: definisce le directory base dove localizzare i packages Spesso utili due directory base per file sorgenti (.java) per file compilati (.class) UNIX: export CLASSPATH=/home/mp/java/src:/home/mp/java/classes:. WINDOWS: set CLASSPATH=c:\home\mp\java\src;\home\mp\java\classes;.