Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoOrlando Bello Modificato 10 anni fa
1
1 Interfacce e polimorfismo Sandro Pedrazzini Approfondimento Interfacce e polimorfismo
2
2 Interfacce e polimorfismo Sandro Pedrazzini Motivazione Importanza del polimorfismo nellutilizzo dei pattern e, più In generale, nella programmazione OO Ruolo degli elementi interface Disaccoppiamento degli elementi Programmazione generica Estensione di funzionalità esistente
3
3 Interfacce e polimorfismo Sandro Pedrazzini Interface Separazione del concetto di interfaccia da quello di classe Più classi possono realizzare la stessa interfaccia Sci calcolaImporto(…) Carving calcolaImporto(…) Bambini calcolaImporto(…) Normale calcolaImporto(…)
4
4 Interfacce e polimorfismo Sandro Pedrazzini Esempio 1: genericità con linterfaccia Icon Java mette a disposizione il metodo showMessageDialog(...) per mostrare un dialogo in interfaccia JOptionPane.showMessageDialog(null,"Hello World");
5
5 Interfacce e polimorfismo Sandro Pedrazzini Scelta dellicona (1) Esistono altri overloading del metodo showMessageDialog(...). Ne scegliamo uno che ci permetta di specificare cosa mostrare come immagine nel messaggio. class JOptionPane extends JComponent implements Accessible {... public static void showMessageDialog( Component parentComponent, Object message, String title, int messageType, Icon icon) {...} }
6
6 Interfacce e polimorfismo Sandro Pedrazzini Scelta dellicona (2) JOptionPane.showMessageDialog( null, "Hello World, message dialog, JOptionPane.INFORMATION_MESSAGE, new ImageIcon(lampadina.gif));
7
7 Interfacce e polimorfismo Sandro Pedrazzini Nuova scelta Supponiamo ora di voler visualizzare nel messaggio una forma grafica senza dover generare precedentemente un file contenente limmagine. Visto che showMessageDialog(...) accetta un elemento di tipo Icon, non siamo obbligati a passare ImageIcon, ma possiamo fornire un oggetto di qualsiasi classe che realizzi linterfaccia Icon.
8
8 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Icon (1) public interface Icon { int getIconWidth(); int getIconHeight(); void paintIcon( Component c, Graphics g, int x, int y); }
9
9 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Icon (2) Uninterfaccia non contiene una realizzazione di funzionalità. Specifica semplicemente un insieme di metodi. Qualsiasi classe che implementi linterfaccia Icon ha due responsabilità: –Fornire la dimensione dellicona –Disegnare licona.
10
10 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Icon (3) Il parametro Component di paintIcon() rappresenta il componente grafico che deve contenere limmagine. Da questo è possibile ottenere alcune proprietà, come il colore dello sfondo, il font, ecc. È quindi possibile disegnare limmagine nellarea grafica (Graphics) in modo che si adatti al contesto in cui viene disegnata.
11
11 Interfacce e polimorfismo Sandro Pedrazzini Implementazione (1) Realizziamo una classe WorldIcon che implementa Icon. La classe disegna un cerchio rappresentante il mondo. Un oggetto di questa classe potrà essere passato al metodo showMessageDialog(), che non ha bisogno di conoscere la classe WorldIcon. Gli basta sapere che si comporta come (implementa) Icon.
12
12 Interfacce e polimorfismo Sandro Pedrazzini Implementazione (2) Icon paintIcon(…) WorldIcon paintIcon(…) ImageIcon paintIcon(…)
13
13 Interfacce e polimorfismo Sandro Pedrazzini Implementazione (2) public class WorldIcon implements Icon{ private int fSize; public WorldIcon(int size){ fSize = size; } public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2 = (Graphics2D)g; Ellipse2D.Double world = new Ellipse2D.Double(x,y,fSize, fSize); g2.setColor(Color.BLUE); g2.fill(world); } public int getIconWidth() { return fSize; } public int getIconHeight() { return fSize; }
14
14 Interfacce e polimorfismo Sandro Pedrazzini Utilizzo JOptionPane.showMessageDialog( null,"Hello World", "message dialog", JOptionPane.INFORMATION_MESSAGE, new WorldIcon(60));
15
15 Interfacce e polimorfismo Sandro Pedrazzini Considerazioni (1) Chi realizza il metodo showMessageDialog() non ha nessuna idea di quale tipo di icona verrà passata. Le classi utilizzate per realizzare licona possono essere completamente diverse. Lunica cosa in comune consiste nellimplementare linterfaccia Icon. Solo quando viene chiamato in showMessageDialog() un metodo di Icon, linterprete Java cerca di identificare il vero tipo delloggetto.
16
16 Interfacce e polimorfismo Sandro Pedrazzini Considerazioni (2) Il polimorfismo è caratterizzato proprio da questa capacità di selezionare il metodo appropriato per un certo oggetto. Un utilizzo importante del polimorfismo consiste nel fornire meccanismi che si comportino come accoppiamento rilassato. Nel nostro caso: il metodo showMessageDialog() non ha bisogno di nessuna informazione di come WorldIcon elabori limmagine. È solamente interessato alle chiamate allinterfaccia Icon. Non esiste nessun accoppiamento tra JOptionPane e WorldIcon.
17
17 Interfacce e polimorfismo Sandro Pedrazzini Considerazioni (3) Quando utilizziamo la classe di una libreria di terzi, prima viene implementata la libreria, poi il nostro programma principale che la utilizza. Quando creiamo una nostra sottoclasse da usare in modo polimorfico, il programma principale che la utilizza può essere stato implementato da terzi ben prima che noi mettiamo a disposizione la nostra funzionalità specifica => Principio del framework
18
18 Interfacce e polimorfismo Sandro Pedrazzini Esempio 2: Comparable Altro esempio di codice generico con lutilizzo del polimorfismo Metodo statico sort() della classe Collections, in grado di ordinare una lista qualsiasi. List list =...; Collections.sort(list);
19
19 Interfacce e polimorfismo Sandro Pedrazzini Comparable (1) I singoli oggetti della lista possono appartenere a una classe qualsiasi, a patto che implementi linterfaccia Comparable. public interface Comparable { int compareTo(T other); } La chiamata a compareTo() restituisce un valore negativo se loggetto invocante precede loggetto parametro, zero se i due oggetti sono uguali e un valore positivo
20
20 Interfacce e polimorfismo Sandro Pedrazzini Comparable (2) Come mai tutti gli oggetti devono essere di tipo Comparable? Perché lalgoritmo di sort, chiamando compareTo() riesce a decidere gli spostamenti degli oggetti, senza dover conoscere il loro vero tipo. Comparable object1 =...; if (object1.compareTo(object2) > 0){ sposta object1 rispetto a object2 }
21
21 Interfacce e polimorfismo Sandro Pedrazzini Comparable (3) Esempio 1: String realizza Comparable List countries = new ArrayList (); countries.add(Switzerland); countries.add(Belgium); countries.add(Germany); Collections.sort(countries);...
22
22 Interfacce e polimorfismo Sandro Pedrazzini Comparable (4) Esempio 2: Realizzazione di una nuova classe public class Country implements Comparable { private String fName; private double fArea; public Country(String name, double area){ fName = name; fArea = area; } public String getName() { return fName; } public double getArea() { return fArea; } Criterio di ordinamento: dimensione della superficie del territorio public int compareTo(Country other) { if (fArea < other.getArea()){ return -1; } if (fArea > other.getArea()){ return 1; } return 0; }
23
23 Interfacce e polimorfismo Sandro Pedrazzini Comparable (5) Utilizzo della classe Country, con ordinamento secondo la grandezza in km 2 public class CountryTry { public static void main(String[] args) { List countries = new ArrayList (); countries.add(new Country("Belgium",77000)); countries.add(new Country("Switzerland",41000)); countries.add(new Country("Uruguay",440000));... Collections.sort(countries); for (Country country : countries){ System.out.println(country.getName() + " " + country.getArea()); }
24
24 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (1) Se ora volessimo ordinare le stesse nazioni dellesempio 2 in base al nome, invece che in base alla superficie, dovremmo ridefinire il metodo compareTo(). Oltre che essere scomodo, ci obbligherebbe a definire sottoclassi unicamente per distinguere diversi metodi compareTo() (modifica del design per scopi che con il design nulla hanno a che vedere)
25
25 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (2) Soluzione: utilizzo di un overloading di sort(), che accetta come secondo parametro un oggetto Comparator Gli oggetti presenti in List vengono ordinati in base allordinamento definito in Comparator. class Collections {... public static void sort(List list, Comparator c) {... }
26
26 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (3) La lista List può ora contenere oggetti di qualsiasi tipo. Non è più necessario che appartengano a classi che implementino uninterfaccia particolare. public class Country { private String fName; private double fArea; public Country(String name, double area){ fName = name; fArea = area; } public String getName() { return fName; } public double getArea() { return fArea; }
27
27 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (4) public class ComparatorByName implements Comparator { public int compare(Country country1, Country country2) { String name1 = country1.getName(); String name2 = country2.getName(); return name1.compareTo(name2); //implementato in String }
28
28 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (5) public class ComparatorByArea implements Comparator { public int compare(Country country1, Country country2) { String area1 = country1.getArea(); String area2 = country2.getArea(); if (area1 < area2){ return -1; } if (area1 > area2){ return 1; } return 0; }
29
29 Interfacce e polimorfismo Sandro Pedrazzini Interfaccia Comparator (6) Utilizzo di ComparatorByName public class CountryTry2 { public static void main(String[] args) { List countries = new ArrayList (); countries.add(new Country("Switzerland", 15000)); countries.add(new Country("Uruguay", 170000)); countries.add(new Country("Belgium", 30000));... Collections.sort(countries, new ComparatorByName()); for (Country country : countries) { System.out.println(country.getName() + " " + country.getArea()); }
30
30 Interfacce e polimorfismo Sandro Pedrazzini Overriding di equals() e hashCode() (1) Una comune sorgente di errore in applicazioni Java consiste nel dimenticare di riscrivere il metodo hashCode() ogni volta che si riscrive equals(). Il metodo hashCode() viene usato quando si ha a che fare con elementi di Collection, come liste e tabelle hash.
31
31 Interfacce e polimorfismo Sandro Pedrazzini Overriding di equals() e hashCode() (2) Il contratto, come specificato in Object, prevede 1.hashCode() deve restituire sempre lo stesso valore se chiamato più volte sullo stesso oggetto (non necessariamente lo stesso tra unesecuzione e laltra) 2.Se due oggetti sono uguali rispetto a equals(), anche i loro metodi hasCode() devono restituire lo stesso risultato 3.Se due oggetti sono diversi, rispetto a equals(), non è detto che hashCode() debba restituire risultati diversi. Se però si fa in modo che anche le hashCode() restituiscono risultati diversi, anche la performance di tabelle hash migliora
32
32 Interfacce e polimorfismo Sandro Pedrazzini Oggetti uguali, stesso hashCode Lerrore più frequente capita con il punto 2: oggetti uguali devono avere lo stesso valore di hash –Capita infatti che due oggetti siano uguali dal punto di vista logico (overriding di equals()), ma dal loro valore di hash sono diversi –Il metodo hashCode() viene ereditato da Object, che assegna un hashCode diverso ad ogni nuovo oggetto (tipicamente convertendo lindirizzo di allocazione in un int, anche se non devessere necessariamente così)
33
33 Interfacce e polimorfismo Sandro Pedrazzini Esempio (1) public class Country { private String fName; private double fArea; public Country(String name, double area){ fName = name; fArea = area; } public String getName() { return fName; } public double getArea() { return fArea; } public boolean equals(Object o) { if (o == this){ return true; } if (!o instanceof Country) { return false; } Country county = (Country)o; return country.getName().equals(fName) && country.getArea() == fArea; }
34
34 Interfacce e polimorfismo Sandro Pedrazzini Esempio (2) Supponiamo ora di voler usare questa classe con HashMap Map population = new HashMap (); population.put(new Country(Switzerland, 15000), 7000000); Ci si aspetterebbe che unespressione del genere restituisca il valore di 7 milioni, invece restituisce null population.get(new Country(Switzerland, 15000)); gli oggetti coinvolti sono 2 e il fatto di aver omesso limplementazione di hashCode() causa un diverso valore per istanze diverse
35
35 Interfacce e polimorfismo Sandro Pedrazzini Esempio (3) Bisogna allora provvedere a fornire un hashCode che sia uguale per istanze equals Variante semplice, ma da non usare !! public int hashCode() { return 150; }
36
36 Interfacce e polimorfismo Sandro Pedrazzini Esempio (4) Un codice fisso è legale perché assicura che oggetti uguali abbiano lo stesso hashCode Non è una buona soluzione, perché fa in modo che TUTTI gli oggetti abbiano hashCode uguale. In questo modo tutti gli oggetti in una hash table avrebbero stessa chiave, facendo degenerare la tabella in una lista semplice, con i costi che ne derivano
37
37 Interfacce e polimorfismo Sandro Pedrazzini hashCode (1) Una buona funzione di hash tende a produrre valori diversi di hash per oggetti diversi Ci sono varie ricette su come generare valori di hashCode Alcuni elementi da considerare: –Cercare di considerare tutti i campi significativi usati in equals() –Tralasciare i campi ridondanti (calcolati da altri campi) –Se un campo è un array, trattarlo come se ogni elemento fosse un campo separato
38
38 Interfacce e polimorfismo Sandro Pedrazzini hashCode (2) Esempio tratto da Bloch, Effective Java –Registra una costante iniziale nella variabile risultato (esempio: 17) –Per ogni campo genera un valore intero »Per ogni elemento di tipo scalare, usare il valore effettivo »byte, char, short, int => (int) f »float => Float.floatToIntBits(f) »long => (int) (f^(f >>> 32) (xor con shift a destra di 4 byte) »Per riferimenti a oggetti che in equals() sono usati attraverso il loro equals(), usare il loro valore di hashCode() –Combinare tutti i valori ottenuti in questo modo: risultato = 31 * risultato + valore Verificare che a istanze uguali corrispondano valori uguali Il valore 31 è scelto perché numero primo. Un vantaggio di 31 consiste nel fatto che la moltiplicazione può essere rimpiazzata da uno shift e sottrazione, più performanti. 31 * i == (i << 5) -i Moderne VM eseguono automaticamente questo tipo di ottimizzazione
39
39 Interfacce e polimorfismo Sandro Pedrazzini Esempio public class Country { private String fName; private double fArea;... public boolean equals(Object o) { if (o == this){ return true; } if (!o instanceof Country) { return false; } Country county = (Country)o; return country.getName().equals(fName) && country.getArea() == fArea; } public int hashCode() { int result = 17; result = 31 * result + fName.hashCode(); long areaCode = Double.doubleToLongBits(fArea); result = 31 * result + (int)(areaCode ^(areaCode >>> 32)); return result; }
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.