29 febbraio 2008 Progettare tipi di dato astratti
Oggetti Servono per definire nuovi tipi di dato collezioni di dati + relative operazioni Vedremo cosa vuol dire dare la specifica e limplementazione di un tipo di dato Vedremo cosa vuol dire astrarre dalla implementazione tramite la specifica
Cosa sta nella specifica? 1) La descrizione astratta dei dati 2) La descrizione delle relative operazioni
La specifica Java (parte sintattica della specifica) –classe o interfaccia per ora solo classi –nome per il tipo nome della classe –operazioni metodi di istanza incluso il(i) costruttore(i) la specifica del tipo descrive proprietà generali degli oggetti –per esempio la modificabilità per il resto la specifica è essenzialmente una specifica dei metodi –strutturata come già abbiamo visto per le astrazioni procedurali –loggetto su cui i metodi operano è indicato nella specifica da this
Formato della specifica public class NuovoTipo { // OVERVIEW: Gli oggetti di tipo NuovoTipo // sono collezioni modificabili di.. // costruttori public NuovoTipo () // EFFECTS:... // metodi // specifiche degli altri metodi }
Esempio Vogliamo realizzare una classe Data i cui oggetti memorizzano giorno, mese, anno(int). Vogliamo che 1<=giorno<=30 1<=mese<= <=anno Vogliamo le seguenti operazioni leggere\modificare giorno, mese, anno
Una possibile specifica public class Data{ //OVERVIEW: una Data memorizza giorno, mese, anno // costruttore public Data(int g, int m,int a){ //REQUIRES: 1 = 2008 //EFFECTS: crea una nuova Data con giorno g, mese //m ed anno a}
Una possibile specifica // metodi public void modifica(int g, int m,int a) { //REQUIRES: 1 = 2008 //MODIFIES:this //EFFECTS: aggiorna il giorno, mese ed anno di //this con g,m ed a rispettivamente } public int getGiorno() { //EFFECTS: restituisce il giorno di this} public int getMese() { //EFFECTS: restituisce il mese di this} public int getAnno() { //EFFECTS: restituisce lanno di this} }
Implementazione scelta fondamentale è quella della rappresentazione variabili distanza che rappresentano lo stato degli oggetti usando tipi primitivi o già implementati nuovi tipi astratti che facilitano limplementazione del nostro segue limplementazione dei costruttori e dei metodi
Una possibile implementazione public class Data{ //OVERVIEW: una Data memorizza giorno, mese, anno public int giorno; public int mese; public int anno; public Data(int g, int m,int a){ //REQUIRES: 1 = 2008 //EFFECTS: crea una nuova Data con giorno g, mese //m ed anno a giorno=g; mese=m; anno=a; }
Una possibile implementazione public void modifica(int g, int m,int a) { //REQUIRES: 1 = 2008 //MODIFIES:this //EFFECTS: aggiorna il giorno, mese ed anno di //this con g,m ed a rispettivamente giorno=g; mese=m; anno=a;} public int getGiorno() { //EFFECTS: restituisce il giorno di this return giorno;} public int getMese() { //EFFECTS: restituisce il mese di this return mese;} public int getAnno() { //EFFECTS: restituisce lanno di this return anno;} }
Ovviamente Limplementazione deve soddisfare la specifica Diverse implementazioni per la stessa specifica
Una implementazione alternativa public class Data{ //OVERVIEW: una Data memorizza giorno, mese, anno public int[] valori; public Data(int g, int m,int a){ //REQUIRES: 1 = 2008 //EFFECTS: crea una nuova Data con giorno g, mese //m ed anno a valori=new int[3]; valori[0]=g; valori[1]=m; valori[2]=a;}
Una implementazione alternativa public void modifica(int g, int m,int a) { //REQUIRES: 1 = 2008 //MODIFIES:this //EFFECTS: aggiorna il giorno, mese ed anno di //this con g,m ed a rispettivamente valori[0]=g; valori[1]=m; valori[2]=a;}} public int getGiorno() { //EFFECTS: restituisce il giorno di this return valori[0];} public int getMese() { //EFFECTS: restituisce il mese di this return valori[1];} public int getAnno() { //EFFECTS: restituisce lanno di this return valori[2];} }
Astrazione tramite specifica I moduli che usano il tipo di dato vedono solo la specifica (interfaccia pubblica) I moduli sono quindi indipendenti dallimplementazione del tipo di dato Necessario per avere moduli indipendenti in cui le modifiche del codice siano il piu possibile locali
Esempio Consideriamo di dovere sviluppare una applicazione in cui dobbiamo confrontare due date public static boolean minore(Data x, Data y) { //EFFECTS: restituisce true se x <=y, false //altrimenti } Minore o uguale in senso ovvio, temporale
Soluzione corretta public static boolean minore(Data x, Data y) { //EFFECTS: restituisce true se x <=y, false //altrimenti if (x.getAnno() < y.getAnno()) {return true;} if (x.getAnno() > y.getAnno()) {return false;} if (x.getMese() < y.getMese()) {return true;} if (x.getMese() > y.getMese()) {return false;} if (x.getGiorno() <= y.getGiorno()) {return true;} else {return false;} } Programmato guardando solo la specifica di Data Non accede alla rappresentazione ===> funziona per tutte le implementazioni
Soluzione sbagliata public static boolean minore(Data x, Data y) { //EFFECTS: restituisce true se x <=y, false //altrimenti if (x.anno < y.anno()) {return true;} if (x.anno > y.anno()) {return false;} if (x.mese < y.mese) {return true;} if (x.mese > y.mese) {return false;} if (x.giorno <= y.giorno) {return true;} else {return false;} } Accede alla rappresentazione ===> funziona solo per una implementazione } Programmato guardando solo la specifica di Data
Rappresentazione Privata Si deve forzare questo stile di programmazione dichiarando sempre le variabili distanza private in questo modo i moduli che utilizzano il tipo di dato sono costretti a programmare astraendo dalla specifica La rappresentazione privata e fondamentale anche per garantire la corretta dellimplementazione
Esempio Vogliamo che tutti gli oggetti di tipo Data memorizzino giorno, mese, anno tali che 1<=giorno<=30 1<=mese<= <=anno Nella progettazione della classe abbiamo garantito tramite pre- condizioni che tutti gli oggetti lo soddisfino Se la rappresentazione fosse pubblica qualsiasi altro modulo del programma potrebbe assegnare valori arbitari a giorno, mese, anno
Esercizio: Part I Implementare la seguente specifica che definisce un tipo di dato Libro Come? Come si vuole ma usando una rappresentazione privata
public class Libro{ //OVERVIEW: un Libro memorizza il titolo (String), //lautore (String), numero di copie (int) public Libro(String t,String a,int n){ //REQUIRES: n >0 //EFFECTS: crea un nuovo Libro con titolo t, //autore a, e numero di copie n } public void somma(int num) { //REQUIRES: num>0 //MODIFIES:this //EFFECTS: aggiorna il numero delle copie sommando //num } public String autore(){ //EFFECTS: restituisce lautore di this} public String titolo(){ //EFFECTS: restituisce il titolo di this}
public int copie(){ //EFFECTS: restituisce il numero di copie di this} public boolean equals(Libro p){ //EFFECTS: restituisce true se this e p // sono uguali, altrimenti false} } uguali ======> hanno lo stesso stato interno
Suggerimento Partire dallo stato degli oggetti (da definire tramite opportune variabili distanza) Poi implementare i metodi
Esercizio: Part II Vogliamo realizzare un modulo che usa il tipo di dato Libro Dei metodi statici che effettuano operazioni su un insieme di Libri (rappresentati come un array di Libro)--biblioteca Vediamo la specifica della classe (da implemenatre)
public class ProcLibro{ //OVERVIEW: definisce metodi statici per //effettuare operazioni su un array di Libri public static boolean cerca(Libro[] b, Libro p){ //EFFECTS: restituisce true se p occorre in b, altrimenti false} public static String cerca(Libro[] b, String a){ //EFFECTS: restituisce il titolo di un Libro //appartenente ad l con autore a, se non ce ne // sono la stringa vuota} public static String all-copie(Libro[] b, String a, String t){ //EFFECTS: restituisce il numero di copiein b del //Libro che ha autore a e titolo t } }
Part III: testing Per testare le due classi e necessario realizzare un metodo main Crea delle istanze di tipo Libro e un array Chiama i metodi delle due classi per verificare il loro funzionamento Gli esercizi vanno finiti a casa (si possono fare benissimo anche sulla carta) Io sono a disposizione per correggerli