29 febbraio 2008 progettare tipi di dato astratti
TRANSCRIPT
29 febbraio 2008Progettare 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 l’implementazione 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– l’oggetto su cui i metodi operano è indicato nella specifica da this
Formato della specificapublic 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<=12 2008<=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<=g<=30, 1<=m<=12, a>= 2008//EFFECTS: crea una nuova Data con giorno g, mese
//m ed anno a}
Una possibile specifica// metodipublic void modifica(int g, int m,int a) {//REQUIRES: 1<=g<=30, 1<=m<=12, a>= 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 l’anno di this} }
}
Implementazione
• scelta fondamentale è quella della rappresentazione
• variabili d’istanza che rappresentano lo stato degli oggetti usando
• tipi primitivi o già implementati• nuovi tipi astratti che facilitano l’implementazione
del nostro
• segue l’implementazione 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<=g<=30, 1<=m<=12, a>= 2008//EFFECTS: crea una nuova Data con giorno g, mese
//m ed anno a
giorno=g; mese=m; anno=a;}
Una possibile implementazionepublic void modifica(int g, int m,int a) {//REQUIRES: 1<=g<=30, 1<=m<=12, a>= 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 thisreturn giorno;} public int getMese() { //EFFECTS: restituisce il mese di thisreturn mese;} public int getAnno() { //EFFECTS: restituisce l’anno di thisreturn anno;} }
}
Ovviamente
• L’implementazione 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<=g<=30, 1<=m<=12, a>= 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 alternativapublic void modifica(int g, int m,int a) {//REQUIRES: 1<=g<=30, 1<=m<=12, a>= 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 thisreturn valori[0];} public int getMese() { //EFFECTS: restituisce il mese di thisreturn valori[1];} public int getAnno() { //EFFECTS: restituisce l’anno di thisreturn valori[2];} }
}
Astrazione tramite specifica
• I moduli che usano il tipo di dato vedono solo la specifica (interfaccia pubblica)
• I moduli sono quindi indipendenti dall’implementazione 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 d’istanza 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 dell’implementazione
Esempio
• Vogliamo che tutti gli oggetti di tipo Data memorizzino giorno, mese, anno tali che
1<=giorno<=30 1<=mese<=12 2008<=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),//l’autore (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 l’autore 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 d’istanza)
• 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