29 febbraio 2008 Progettare tipi di dato astratti

Preview:

Citation preview

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

Recommended