Programmazione a Oggetti Modulo B Design Pattern Dott. Alessandro Roncato 18/10/2011
Design Patters I Design Patters sono soluzioni di progettazione standard e ben collaudate che possono essere usate in contesti diversi. Vedremo oggi i seguenti: Information Expert Creator Null Object 2
Information Expert D: Come assegnare le responsabilità? R: All'oggetto che ha le informazioni per farlo! Questo è uno dei pattern più naturali nella programmazione ad oggetti e dovrebbe essere la prima ipotesi di soluzione Riduce la dipendenza e di solito aumenta la coesione 3
Esempio Cominciamo dal caso d'uso stornascontrino Oggetti Candidati: Cassiere, Scontrino, Negozio, Carrello, Scaffale, Lotto 4
Cassiere Pro: Contro: Nel applicazione attiva la procedura per stornare lo scontrino Ha alcune informazioni necessarie Nella PO gli oggetti sono passivi, quindi non è importante chi fa l'operazione, ma chi la subisce Non ha molte informazioni necessarie 5
Fine Storna Scontrino? Negozio: Ha alcune informazioni necessarie MA non ha molte altre informazioni necessarie e inoltre scegliendo questo oggetto in altri casi simili si otterrebbe un codice procedurale Carrello: molte informazioni Scaffale, Lotto: non hanno informazioni 6
Scontrino E' l'oggetto che subisce l'operazione Ha tutte delle informazioni necessarie E' la nostra scelta secondo il pattern Information Expert 7
Diagramma classi (parziale) 8
Diagramma di sequenza Scontrino storrnascontrino E adesso??? 9
Storna Scontrino Cosa bisogna fare per stornare lo scontrino: Verificare che il scontrino fosse effettivamente stato emesso dal cassiere, per il cliente Che sia stato emesso in data odierna Ritirare i prodotti presenti nello scontrino Ritornare i contanti o annullare il pagamento Emettere documento di ristorno Eliminare punti 10
Verificare scontrino Chi fa questa verifica? Chi ha le informazioni per farlo? Lo Scontrino stesso in maniera semplice può fare questa verifica Lo Scontrino può anche controllare la data di emissione 11
Esempio public class Scontrino { private Cliente cliente; private Carrello carrello; private Calendar data; public boolean verifica(cliente c) { //if (c!=null) vedremo più avanti return c.equals(cliente); public boolean isodierno(){ return now().get(day)==data.get(day) && now().get(month)==data.get(month) && now().get(year)==data.get(year); 12...
Ritirare i prodotti L'oggetto Prodotto è quello che può fare questa cosa. public class Prodotto { private Scaffale scaffale; public void ritornato(){ scaffale = negozio.getprossimoscaffalelibero();... 13
Ritornare i contanti o... L'oggetto Scontrino è quello che può fare questa cosa. public class Scontrino { private double totale; private PagamentoCarta pagamento; public boolean ristorna(){ if (pagamento!=null) //vedremo D.P. Null Object pagamento.annulla(); else { Negozio.cassa -=totale; //vedremo... System.out.println( ritorna +totale+ ) 14
Diagramma di sequenza Scontrino Prodotto Negozio Pagamento v=verifica(cliente) b=isodierno() [v &&bb] ritornato(utente) getprossimoscaffalelibero [v && b && pagamento!=null] annulla 15
Diagramma di sequenza Scontrino v=verifica(cliente) Prodotto Negozio b=isodierno() [v &&b] ritornato(utente) getprossimoscaffalelibero [v && b && pagamento==null] 16
Ritornare i contanti o... L'oggetto Scontrino è quello che può fare questa cosa. public class Scontrino { private double totale; private PagamentoCarta pagamento; public void ristorna(){ if (pagamento!=null) //vedremo D.P. Null Object pagamento.annulla(); else { Negozio.paga(totale); //vedremo... System.out.println( ritorna +totale+ ) 17
Diagramma di sequenza Scontrino v=verifica(cliente) Prodotto Negozio b=isodierno() *[v &&bb] ritornato(utente) getprossimoscaffalelibero [v && b && pagamento==null] paga(totale) 18
Codice Java public class Scontrino { public void ristorna(cliente c) { boolean v = verifica(c); boolean b = isodierno(); if (v && b) { for (Prodotto p: carrello) p.ritornato();. 19
Emetti Scontrino Abbiamo visto come trattare il caso d'uso Storna Scontrino Come ci comportiamo con il caso simmetrico Emetti Scontrino? La differenza sostanziale è che l'oggetto Scontrino deve ancora essere creato e quindi I.E. non può essere applicato 20
Chi crea gli oggetti? Il pattern Information Expert ci dice che le operazioni devono essere fatte dagli oggetti che sono più esperti. Anche nella creazione dovrebbe essere naturale che il più esperto sia l'oggetto stesso Ma finché non abbiamo un oggetto non possiamo applicare il pattern I.E. 21
Esempio static public class Scontrino { public Scontrino( Carrello c, Cliente cc, double totale) { public static Scontrino emetti(carrello c, Cliente cc){ //Calcola totale return new Scontrino(u,l,totale); 22
static Gli attributi e il codice statici non hanno bisogno di oggetti e quindi possono godere di vita propria Scontrino.emetti(utente,libro); Non sfruttano i benefici della programmazione a oggetti No polimorfismo Vedremo come PO riduce al minimo i metodi statici Sposta il problema: chi invoca emetti? 23
Pattern Creator D: Chi crea un oggetto A? R: L'oggetto B che: C1: B contiene A C2: B aggrega A C3: B memorizza A C4: B che ha le informazioni per farlo B B B A A A 24
Esempio C1 Chi crea gli oggetto Date? Con Creator, l'oggetto Scontrino è il candidato ideale per creare il Date dato che lo Scontrino contiene il Date Scontrino contiene * Date N.B. Un oggetto Date ha lo stesso tempo di vita dell'oggetto Scontrino quindi viene creato e distrutto assieme allo Scontrino 25
Nel codice public class Scontrino { Date data;... public Scontrino(...){... data=new Date();... 26
Esempio C2 Chi crea gli oggetto Prodotto? Con Creator, l'oggetto Scaffale è il candidato ideale per creare l'oggetto Prodotto dato che lo Scaffale contiene i Prodotti Scaffale aggrega * Prodotto N.B. Un oggeto Prodotto può essere riusato da altri oggetti (es. Carrello). Un oggetto Date non può essere riusato da altri oggetti. 27
Nel codice public class Scaffale { Set<Prodotti> prodotti=new...;... //in qualche metodo public void addprodotto(...){ Prodotto p=new Prodotto(...); prodotti.add(p); 28
Esempio C3 Chi crea l'oggetto a Scontrino? Con Creator, l'oggetto Carrello è il candidato ideale per creare lo Scontrino dato che memorizza un riferimento all'oggetto Scontrino Carrello 1 0..1 Scontrino 29
Nel codice public class Carrello { Scontrino scontrino=null;... //in qualche metodo scontrino= new Scontrino(...); 30
Carrello con Scontrino? Vediamo ora un nuovo problema. Per verificare chi se un Carrello e' stato acquistato o meno dobbiam prima di tutto capire come rappresentare quando un Carrello non è stato acquistato. Carrello 0..1 Scontrino 31
Esempio public class Carrello { Scontrino scontrino=null; public Scontrino getscontrino() { return scontrino; 32
Esempio public class Carrello { Scontrino scontrino=null; public boolean isvenduto() { return scontrino!=null; 33
Pro e contro 2 scelte getscontrino in genere è la scelta migliore nella programmazione a oggetti (estensibilità, oltre a trovare facilmente il valore isvenduto, possiamo trovarne anche altre proprietà di interesse dello Scontrino) IsVenduto e' piu' chiaro dal punto di vista logico e nasconde dettagli implementativi 34
Carrelli non venduti Come rappresentare lo Scontrino dei Carrelli non venduti? La scelta più ovvia è quella di utilizzare il valore null In questo modo si deve sempre controllare che il riferimento sia non nullo 35
Esempio null public class Carrello { Scontrino scontrino=null; public double gettotale() { if (scontrino==null) return 0; else return scontrino.gettotale(); 36
IsVenduto La modifica riguarda solamente il metodo stesso, mentre il resto delle classi non viene modificato. Mentre, il metodo getscontrino non viene modificato, ma... 37
getscontrino Più scomoda è la prima alternativa, quella in cui ritorniamo lo Scontrino relativo al Carrello Nel caso il Carrello non sia stato venduto, viene ritornato il riferimento null. Quindi chi usa il metodo pubblico deve essere a conoscenza di questo! Quindi ANCHE il codice delle altre classi deve ricordasarsi di questo fatto! 38
Pattern Null Object D: Come rappresentare le associazioni senza elementi? R: Si crea un oggetto denominato Null Object e si usa il riferimento a questo oggetto per indicare la mancanza di elementi 39
Esempio Null Objetc public class Carrello { Scontrino scontrino=scontrinonullo.istanza; public Scontrino getscontrino() { return scontrino; public boolean storna(){ scontrino=scontrinonullo.istanza;... 40
Esempio Null Objetc public class ScontrinoNullo extends Scontrino { public ScontrinoNullo(){ public static ScontrinoNullo istanza= new ScontrinoNullo(); public void gettotale(){return 0;... Attenzione: Null Object!=null. Null Object è un oggetto a tutti gli effetti e con questo pattern rappresenta l'oggetto speciale diverso da tutti gli altri che rappresenta un oggetto vuoto/nullo 41
Vantaggi Null Object Nel codice di tutta l'applicazione possiamo evitare di controllare se il puntatore ritornato da getscontrino sia diverso da null. return c.getscontrino().gettotale() Invece di if (c.getscontrino()!=null) return c.getscontrino().gettotale() else return... Svantaggi: una classe in più! 42
Esame Attenzione: all'esame scritto almeno un esercizio ha a che fare con (una versione modificata di) questo pattern. ListaVuota AlbertoVuoto L'idea di fondo è sempre la stessa. 43
Carrelli non venduti Nel nostro caso come rappresentare i Carrelli non venduti? Se pensiamo di associare al Carrello all'ogetto Cliente che lo ha acquistato una scelta alternativa è quella di ritornare come Cliente il Negozio stesso Per fare questo bisogna che Negozio e Cliente abbiano qualcosa in comune ovvero che estendano/implementino una stessa classe/interfaccia 44
Nel Diagramma Carrello compratoda Entità Cliente Negozio 45
Nel codice public interface Entita { public class Cliente implements Entita { public class Negozio implements Entita { 46
Nel codice public class Carrello { Entita compratoda=negozio.istanza; public Entita getcompratoda() { return compratoda; 47
Soluzione più semplice Tutti gli oggetti Java estendono Object PRO: Non serve una classe/interfaccia in più CONTRO: Meno leggibile, Meno estensibile (non posso aggiungere metodi all'entità, posso solo controllarne l'uguaglianza con il metodo equals) 48
Soluzione semplice public class Carrello { Object compratoda=negozio.istanza; public Object getcompratoda() { return compratoda; 49
Nel Diagramma Carrello compratoda Object Cliente Negozio 50
Progetto: Elencare tutti i casi d'uso Disegnare il diagrammi delle classi Disegnare i diagrammi di sequenza per ogni caso d'uso Utilizzare per quanto possibile il pattern Information Expert 51
Vedremo Come gestire lanegozio (unico oggetto usato da tutti gli altri) e le istanze singole come quelle nel patter Null Object Come gestire i comportamenti diversi dei vari Prodotti (alternative basate sul tipo degli oggetti) 52
Attenzione Solitamente diagrammi UML e codice non vengono fatti nella stessa fase dello sviluppo Prima si fanno i diagrammi e solo successivamente si scrive il codice. In queste lezioni, li vediamo insieme per rendere evidente le implicazioni sul codice delle varie scelte di progettazione 53
Attenzione 2 Quello che vediamo nei diagrammi ha un diretto impatto nel codice ma non lo determina univocamente. Vedremo come sarà possibile implementare i metodi con la stessa firma in modo diverso Le implementazioni viste e che vedremo sono a titolo di esempio e quelle più naturali ma non per questo le uniche corrette 54
domande 55