Proge&azione Proge&azione ad ogge- • Gli ogge- sono astrazioni di en2tà reali o di sistema – In alcuni casi, ci potrebbe essere una corrispondenza ovvia tra en2tà del mondo reale e ogge- • Gli ogge- sono indipenden2 e incapsulano il loro stato – Le funzionalità del sistema sono espresse a&raverso le operazioni offerte dagli ogge- – Le aree da2 condivise sono limitate e gli ogge- comunicano a&raverso messaggi – Gli ogge- possono essere distribui2 e possono essere esegui2 in sequenza o in parallelo • Gli ogge- sono potenzialmente componen2 riusabili Come iden2ficare gli ogge- • L’iden2ficazione degli ogge- (classi) è la parte più difficile della proge&azione a ogge- • Non esiste una “formula magica” – Ci si basa su euris2che, abilità, esperienza e conoscenza del dominio applica2vo • L’iden2ficazione degli ogge-/classi è un processo itera2vo – Solitamente non si finisce con una sola iterazione – Dis2nzione tra ogge-/classi del dominio e della soluzione Approcci possibili • Approccio gramma2cale basato su una descrizione del sistema in linguaggio naturale • Iden2ficazione degli “elemen2 tangibili” del dominio applica2vo • Approccio “comportamentale” per iden2ficare gli ogge- in funzione di chi partecipa a quale comportamento • Approccio basato su scenari per iden2ficare gli ogge-, a&ribu2 e metodi in ogni scenario • Modellazione dei da2 (schema ER) completata con le operazioni • Altri metodi … Analisi e proge&azione • Metodi e notazioni simili • Analisi ojbect-‐oriented – Modellazione del problema • Proge&azione object-‐oriented – Modellazione della soluzione • Spesso gli elemen2 iden2fica2 in fase di analisi migrano (rivis2) nella soluzione • Il confine tra analisi e proge&azione non è ne&o Analisi e proge&azione OO Design Proge&azione • La “corre&ezza” del proge&o è fondamentale – ma possiamo anche valutarlo in funzione della sua “bontà”, efficienza, modificabilità, stabilità, ecc. • Possiamo valutare un proge&o usando – Accoppiamento, coesione e principio open-‐closed Accoppiamento (coupling) • Ca&ura il grado di interconnessione tra classi • Un alto grado di accoppiamento significa – Alta interdipendenza tra le classi – Difficoltà di modifica della classe singola • Un basso accoppiamento è requisito fondamentale per creare un sistema comprensibile e modificabile • Nel mondo ad ogge- abbiamo tre 2pi di coupling: interac2on, component e inheritance Interac2on coupling • Si ha quando metodi di una classe chiamano metodi di altre classi • Le forme peggiori si hanno quando un metodo – Manipola dire&amente le variabili di stato di altre classi – Scambia informazioni a&raverso variabili temporanee • Altre forme (minori) si hanno quando i metodi comunicano dire&amente via parametri – I metodi dovrebbero passare la minor quan2tà di informazione possibile a&raverso il minor numero di parametri Component coupling • Quando una classe A ha – A&ribu2 di un’altra classe C – Parametri di 2po C – Metodi con variabili locali di 2po C • Quando A è accoppiata con C, è accoppiata anche con tu&e le sue so&oclassi • Component coupling solitamente implica anche la presenza di interac2on coupling Inheritance coupling • Quando una classe è so&oclasse di un’altra • La forma peggiore si ha quando una so&oclasse cambia la segnatura di un metodo ereditato – Meglio se la segnatura resta la stessa, ma cambia l’implementazione • Ancor meglio se la so&oclasse aggiunge solo metodi e a&ribu2, ma non modifica nulla Esempio Coesione • Conce&o intra-‐modulo • Si concentra sul perché gli elemen2 stanno nello stesso modulo – Solo gli elemen2 fortemente correla2 dovrebbero stare nello stesso modulo – Il modulo rappresenterebbe una chiara astrazione e sarebbe più semplice da capire • Alta coesione solitamente porta a basso accoppiamento • Tre 2pi di coesione: method, class e inheritance Method cohesion • Come la coesione all’interno di una funzione C – La forma migliore si ha quando un metodo implementa una funzione singola e chiaramente definita – Si dovrebbe poter descrivere il compito del metodo con una sola (semplice) frase Class cohesion • Una classe dovrebbe rappresentare un solo conce&o e tu&e le proprietà dovrebbero contribuire alla sua rappresentazione • Se si incapsulano conce- diversi (nella stessa classe), la coesione diminuisce • Gruppi di metodi diversi che accedono a gruppi di a&ribu2 disgiun2 rappresentano un chiaro sintomo di bassa coesione Inheritance cohesion • L’ereditarietà potrebbe essere indo&a dalla necessità di – Generalizzazione/specializzazione – Riuso • La coesione è maggiore se la gerarchia viene usata per ges2re la generalizzazione/ specializzazione Metriche • Weighted Methods per Class (WMC) – La complessità di una classe dipende dal numero di classi e dalla loro complessità • Supponiamo che la classe C abbia i metodi M1, M2, …, Mn • Supponiamo che la complessità dei metodi sia c1, c2 • WMC = Σ ci • Chiaramente se la complessità di ogni metodo fosse 1, WMC sarebbe pari al numero di metodi della classe – Un WMC alto potrebbe significare propensione ai dife- più elevata Metriche • Una gerarchia di classi profonda significa – Più metodi potenzialmente riusabili – Alta coesione e quindi difficoltà di cambiamento • Depth of Inheritance Tree (DIT) – Il DIT di una classe è la distanza (shortest path) della classe dal nodo radice – Il valore di DIT aiuta a predire la predisposizione ai dife- di una classe Metriche • Number of Children (NOC) – Numero di so&oclassi immediate della classe – Valuta il grado di riuso – Un NOC alto indica riuso delle definizioni da parte di un elevato numero di so&oclassi – Indica anche l’influenza di una classe su altri elemen2 (le use so&oclassi) • Alta influenza impone una proge&azione e una implementazione accurata – Classi con NOC elevato non dovrebbero essere causa d’errore Metriche • Coupling Between Classes (CBC) – Riduce la modularità e rende i cambiamen2 più complessi – CBC = Numero di classi con cui la classe C è accoppiata • Due classi sono accoppiate se i metodi dell’una usano metodi o a&ribu2 dell’altra – Può essere calcolato sul codice • Ci sono forme dire&e di accoppiamento che non possono essere calcolate sta2camente – Può fornire una previsione della dife&osità della classe Metriche • Response for a Class (RFC) – Il numero totale di metodi che possono essere invoca2 da un ogge&o della classe – RFC è la cardinalità del response set della classe • Insieme di tu- i metodi che possono essere invoca2 quando si manda un messaggio a un ogge&o della classe – Tu- i metodi della classe e tu- i metodi invoca2 da ques2 • Anche se il CBC di una classe è 1, il suo RBC potrebbe essere alto – Ca&ura il “peso” delle connessioni – Il test di classi con RFC elevato è più complesso Metriche • Lack of Cohesion in Methods (LCOM) – La coesione ca&ura la “vicinanza” tra i metodi di una classe • Due metodi formano una coppia coesa se accedono a variabili/a&ribu2 comuni • Formano una copia non coesa se non ci sono variabili in comune • L’alta coesione è auspicabile – LCOM è il numero di coppie di metodi che sono non coesi meno il numero di coppie coese – Non significa2vo per predire la possibile dife&osità della classe Gli studi dicono che (I) • Weighted Methods per Class (WMC) – La maggior parte delle classi ha un numero limitato di metodi • Le classi sono semplici e forniscono astrazioni e operazioni specifiche • Solo un numero limitato di classi ha mol2 metodi – Ha una correlazione significa2va con la propensione agli errori • Depth of Inheritance (DIT) – Le classi sono solitamente “vicine” alla radice • DIT massimo vicino a 10 • La maggior parte delle classi ha DIT uguale a 0 (sono la radice) – I proge-s2 tendono a tenere il numero di livelli d’astrazione basso, quindi sacrificano la riusabilità a favore della comprensibilità • Number of Children (NOC) – Le classi di solito hanno un numero limitato di figli, e in mol2 casi NOC vale 0 – L’ereditarietà non è spesso sfru&ata a pieno Gli studi dicono che (II) • Coupling Between Classes (CBC) – La maggior parte delle classi sono auto-‐contenute (CBC = 0), ovvero non sono accoppiate con nessuno – Gli ogge- di interfaccia tendo ad avere un CBC più grande • Response for a Class (RFC) – La maggior parte delle classi usa/invoca pochi metodi di altre classi – Le classi degli ogge- di interfaccia hanno un RFC maggiore • Lack of Cohesion in Methods (LCOM) – Non molto u2le per predire la propensione alla dife&osità Principi di proge&azione Sintomi di un proge&o “mal fa&o” • Rigidità è la tendenza del sokware ad essere difficile da cambiare, anche in modo semplice – Ogni cambiamento provoca una cascata di cambiamen2 in sequenza nei moduli dipenden2 • Fragilità è la tendenza del sokware a “rompersi” in mol2 pun2 ogni volta che viene cambiato – Spesso il problema si verifica in par2 del programma non logicamente correlate al cambiamento • Immobilità è l’incapacità a riusare sokware da altri proge- o da altre par2 dello stesso proge&o • Viscosità si verifica quando l’uso di scorciatoie (hack) è più facile dell’uso dei metodi che rispe&ano il proge&o – È facile fare la cosa sbagliata, difficile fare quella giusta – La viscosità dell’ambiente è data da un ambiente di sviluppo lento e inefficiente Ges2one delle dipendenze • I qua&ro sintomi elenca2 nel lucido precedente sono causa2, dire&amente o indire&amente, da dipendenze improprie tra i moduli del sokware – Quando si ha un degrado nella stru&ura (archite&ura) del sokware, si ha anche un degrado della sua manutenibilità • Le dipendenze tra moduli vanno ges2te a&raverso apposi2 firewall – Le dipendenze non devono propagarsi oltre i firewall Alcuni principi di proge&azione Principio Open-‐Closed • Un modulo dovrebbe essere aperto alle estensioni, ma chiuso alle modifiche • Derivato dal lavoro di Bertrand Meyer, in sostanza, dice – Dovremmo sempre scrivere le nostre classi in modo che siano estendibili, senza che debbano essere modificate • Vogliamo essere capaci di cambiare il comportamento delle classi senza cambiarne il codice sorgente • Il vantaggio in manutenzione è ovvio: se non modifico, non faccio errori • Principi base: ereditarietà, overriding, polimorfismo e binding dinamico Esempio ben noto typedef struct …Figura; Figura figure[100]; Triangolo Trapezio Re&angolo Cerchio figure[1] = “re&angolo”; figure[2] = “triangolo”; figure[3] = “cerchio”; void disegnaTu&o(Figura figure[]) { figure[4] = “trapezio”; for (i= 0; i<100; i++) { if (figure[i] è “re&angolo”) “disegna re&angolo” if (figure[i] è “triangolo”) “disegna triangolo” if (figure[i] è “cerchio”) “disegna cerchio” if (figure[i] è “trapezio”) “disegna trapezio” } } Il codice già definito per disegnaTu&o deve cambiare per Figura potere supportare il nuovo 2po!!! Open/closed? • Quindi la proge&azione tradizionale non verifica open-‐closed – Il modulo disegnaTu&o è aperto a estensioni, ma solo tramite modifica: non è chiuso rispe&o alle modifiche • Come si può fare a rispe&are open/closed? Aggiungiamo la classe Trapezio Figura Cerchio Re&angolo Triangolo Trapezio Figura[] figure = new Figura[100]; figure[1] = new Re&angolo(); figure[2] = new Triangolo(); figure[3] = new Cerchio(); figure[4] = new Trapezio(); disegnaTu&o(figure); public sta2c void disegnaTu&o(Figura[] figure) { for (i= 0; i<100;i++) figure[i].disegna(); } Il Codice definito per Figura non cambia!!! Estendibile se…. • Estendibilità tramite ereditarietà è garan2ta solo se possiamo usare ogge- di una classe che sono “sos2tuibili” a quelli della sopraclasse • Infa- gli ogge- della classe devono rispe&are il contra&o della superclasse – Ad esempio, la disegna() deve contenere codice che disegna l’ogge&o this sullo schermo – Ogni so&oclasse di Figura deve definire una disegna() che abbia lo stesso effe&o! – Ma se si definisse disegna() in modo diverso? • Ad esempio, se disegna() di Trapezi fosse definita in modo che disegna this solo se l’area è maggiore di 20? Va ancora bene? 33 Liskov Subs2tu2on Principle • Gli ogge- della so&oclasse devono rispe&are il contra&o della superclasse – Significa che il comportamento della so&oclasse deve essere “compa2bile” con la specifica della sopraclasse – Ma il metodo può essere esteso per coprire ulteriori casi • Moduli che usano ogge- di un 2po devono potere usare ogge- di un 2po derivato senza accorgersi della differenza – Il contra&o della superclasse deve essere onorato da tu&e le so&oclassi Esempi • Quadrato e Re&angolo • Ortaggio e OrtaggioStagionale • Persona e Studente Dependency Inversion Principle • Dependere dalle astrazioni, non dagli elemen2 concre2 – Dipendere da interfacce e classi astra&e, non da metodi e classi concrete – Principio fondante del conce&o di proge&azione per componen2 (component design) • CORBA, EJB, etc. … in altre parole • Ogni classe C che si ri2ene possa essere estesa in futuro, dovrebbe essere definite come so&o2po di un'interfaccia o di una classe astra&a A • Tu&e le volte che non è stre&amente indispensabile riferirsi ad ogge- della classe concreta C, è meglio riferirsi invece a ogge- il cui 2po sta2co è A, non C • In questo modo, sarà più facile in seguito modificare il codice client per u2lizzare invece di C altre classi concrete so&o2pi di A Minimizzazione dell’interfaccia • Se non esiste una ragione forte per dire che un metodo è pubblico, lo dichiariamo privato • Definiamo solo metodo ge&er (e non se&er) per i campi della classe se possibile • Non dobbiamo replicare completamente la stru&ura da2 contenuta in una classe nella sua interfaccia Ereditarietà e delega List List + add() + remove() + add() + remove() Stack Stack + push() + pop() + top() + push() + pop() + top() Ulteriori principi • The Interface Segrega2on Principle: Many client specific interfaces are be&er than one general purpose interface • The Reuse/Release Equivalency Principle: The granule of reuse is the same as the granule of release. Only components that are released through a tracking system can be effec2vely reused • The Acyclic Dependencies Principle: The dependency structure for released components must be a directed acyclic graph. There can be no cycles • The Stable Dependencies Principle: Dependencies between released categories must run in the direc2on of stability. The dependee must be more stable than the depender • The Stable Abstrac2ons Principle: The more stable a class category is, the more it must consist of abstract classes. A completely stable category should consist of nothing but abstract classes Metodi con pochi parametri • Oltre i tre o qua&ro si rischia che i programmatori non se li ricordino – Nonostante l’assistenza fornita dagli IDE, i metodi con troppi parametri rimangono incomprensibili • Par2colarmente pericolose sono le liste di parametri dello stesso 2po – Un’inversione non genera errori di compilazione ma provoca malfunzionamen2 difficilmente diagnos2cabili Metodi con pochi parametri • Un metodo che richiede mol2 parametri può generalmente essere spezzato in metodi che richiedono ciascuno meno parametri • Possiamo creare classi ausiliarie che contengano gli aggrega2 dei parametri – Questa tecnica è raccomandabile quando si hanno sequenze di parametri ricorren2 che rappresentano sempre la stessa en2tà An2-‐pa&ern • Un an2-‐pa&ern è una soluzione usata spesso, ma che dovrebbe essere evitata – È un errore comune – Dovrebbe fornire suggerimen2 su come migliorare il codice o evitare errori no2 • Gli an2-‐pa&ern non si applicano solo alla proge&azione a ogge- Esempio • Classe Blob – Una sola classe enorme che con2ene la maggior parte della logica applica2va – Deriva spesso dall’adozione di una proge&azione procedurale Refactoring • È abbastanza difficile fare la cosa giusta al primo colpo – Spesso le soluzioni trovate richiedono refactoring – Ovvero il miglioramento del proge&o del codice esistente senza cambiarne il comportamento • Miglioramen2 al codice/archite&ura – Piccoli miglioramen2 – Test di regressione con2nuo • Framework Junit Refactoring • Il tempo e la manutenzione potrebbero rendere disordinato il codice • Codice disordinato riduce le possibilità di manutenzione • Il refactoring rinfresca/pulisce il codice senza cambiarne le funzionalità – Migliora la coesione e riduce l’accoppiamento – Applica i pa&ern – Rimuove gli an2-‐pa&ern – O-mizza le prestazioni (velocità e memoria) – Aggiunge commen2 (magari a&raverso JavaDocs) Quando fare refactoring • Non esiste regola precisa • Quando si intravedono problemi – Par2 di codice par2colarmente difficili – Par2 troppo complesse – Par2 con an2-‐pa&ern eviden2 • Meglio fare refactoring prima di aggiungere nuove funzionalità o cambiare le esisten2 Problemi no2 (I) • Codice duplicato – Estrarlo, parametrizzarlo e farlo diventare un metodo di servizio – Codice simile in so&oclassi correlate • Spostare il codice comune come metodo della superclasse • Metodi lunghi – Se il codice di un metodo diventa troppo lungo per poterlo capire facilmente, bisogna estrarne delle par2 come metodi di servizio Problemi no2 (II) • Funzionalità e da2 – Se un metodo usa principalmente i da2 di un’altra classe, bisogna spostare il metodo nella classe in cui sono defini2 i da2 • Uso di Switch – Spesso indicano un 2po – L’introduzione di nuovi 2pi richiede la modifica degli switch rela2vi – Bisognerebbe usare ereditarità, enum, pa&ern (State) Problemi no2 (III) • Blocchi di da2 – Da2 che sono solitamente usa2 insieme – Potrebbero portare a una lunga lista di parametri (altro problema) – Bisognerebbe introdurre una classe per contenere i da2 correla2 • Commen2 – Par2 di codice con commen2 significa2vi potrebbero diventare metodi con un nome auto-‐ esplica2vo Programmazione Codice riusabile, manutenibile ed estendibile Metodi di piccole dimensioni • Metodi di dimensioni limitate possono essere le- e compresi in modo abbastanza agevole – Metodi brevi e chiari richiedono pochi commen2 o possono non richiederne affa&o – Di solito si riesce a mantenere la maggior parte dei metodi al di so&o delle 20 righe di codice – Raramente è necessario scrivere metodi più lunghi di 40 righe Pa&ern s2lis2ci • Sono pra2che riguardan2 la scri&ura del codice, non la proge&azione • Spesso, sono supporta2 dall’IDE • Spesso, sono verificabili • È bene prendere le buone abitudini subito • È giusto concordare alcune pra2che nel gruppo di lavoro Commen2 • Il codice è troppo di basso livello • I commen2 possono essere usa2 per chiarire il significato del codice o per renderlo ancora più oscuro! – I commen2 che ripetono il codice sono inu2li – I commen2 che contraddicono il codice indicano che probabilmente sia codice che commen2 sono scorre- – I commen2 possono indicare il significato del codice in modo parzialmente indipendente da cambiamen2 – I commen2 devono indicare cosa il codice si propone di fare Esempi • Commento inu2le: i++; // Increment i • Commento u2le: i++; // Increment the card counter. • Qui non c’è bisogno di commento: cardCounter++; • Una buona scelta dei nomi delle variabili, dei metodi, ecc. rende il codice largamente “autocommentato” Dove/cosa commentare • Cosa commentare dipende da molteplici fa&ori, in par2colare dall’espressività del linguaggio – In Java generalmente non è il caso di avere un commento per ogni riga di codice • Nei linguaggi OO è generalmente una buona idea fornire un commento all’inizio di ogni metodo, che de&agli il significato del metodo, eventuali vincoli, requisi2 ecc. – Può essere u2le riportare anche riferimen2 a documentazione esterna – Al solito, dare un nome significa2vo ai metodi può semplificare il commento Quando commentare • Occorre commentare quando è necessario dire qualcosa con maggiore chiarezza di quanto non possa fare il codice • Se si può rendere il codice abbastanza chiaro da poterlo considerare autocommentato, questo è ciò che va fa&o! – Valutare sempre la conoscenza di chi leggerà il codice – Se l’informazione per comprendere il codice si trova “vicino” allora il codice può essere considerato comprensibile Nomi e maiuscole • Si può fare in modo che il nome di un elemento indichi la natura dell’elemento • Questo effe&o si o-ene mediante delle “convenzioni di programmazione”, solitamente stabilite a livello aziendale • In modo più ar2gianale, si possono usare le maiuscole in modo convenzionale per comunicare informazioni Maiuscole e Java • Nomi di classi e interfacce hanno l’iniziale maiuscola: Stack • Nomi di variabili e metodi iniziano sempre con una minuscola: push(...). • I nomi delle costanto sono completamente maiuscoli: java.lang.Math.PI; • I nomi di package sono scri- in minuscolo: java.lang • Se il nome è composto da più parole, ciascuna di queste è scri&a con l’iniziale maiuscola: mustCopyToRunstack(...) – L’uso di “underscore” (must_copy_to_runstack) non è consigliato Uso consistente dei nomi • I nomi delle classi dovrebbero essere singolari: Stack • I metodi void dovrebbero avere per nome dei predica2 verbali che descrivono cosa fanno: openFiles() • I metodi e le variabili boolean dovrebbero avere nomi che iniziano con una declinazione di “essere”: isFinished() • Gli altri metodi non void dovrebbero avere nomi che suggeriscono cosa res2tuiscono: sizeOfFigure() • Variabili non boolean dovrebbero avere nomi cos2tui2 da sostan2vi (eventualmente con agge-vo): age Codice comprensibile • Codice semplice, ma cosa fa? public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1; } Meglio? public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] cell : gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); return flaggedCells; } Così? public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells; } Abbiamo • Usato nomi significa2vi per spiegare le intenzioni – flaggedCells invece di list1 • Sos2tuito numeri magici con costan2 – cell[STATUS_VALUE] invece di x[0] • Creato un ADT opportuno – Cell cell invece di int[] cell Ogni metodo una cosa sola public bool isEdible() { if (this.ExpirationDate > Date.Now && this.ApprovedForConsumption == true && this.InspectorId != null) { return true; } else { return false; } } 1. 2. 3. 4. Controlla la scadenza Controlla l’approvazione Controlla l’ispezione Risponde alla richiesta Meglio così public bool isEdible() { return isFresh() && isApproved() && isInspected(); } • Ora il metodo fa una cosa sola • Un cambiamento nella specifica richiederebbe un solo cambiamento nel codice Non mischiare livelli d’astrazione public void doTheDomesticThings() { takeOutTheTrash(); walkTheDog(); for (Dish dish : dirtyDishStack) { sink.washDish(dish); teaTowel.dryDish(dish); } } public void doTheDomesticThings() { takeOutTheTrash(); walkTheDog(); doTheDishes(); } Usare le eccezioni • Gli errori devono essere codifica2 • I controlli richiedono codice • Codice difficile da estendere public int foo(){ ... } public void bar(){ if(foo() == OK) ... else // error handling } Con le eccezioni • Non si mischiano valori res2tui2 e di controllo • Sintassi più chiara • Codice facile da estendere public void foo() throws FooException{ ... } public void bar(){ try{ foo(); ... } catch(FooException){ // error handling } } Alcuni errori comuni • Crescita del codice – Metodi lunghi e classi grandi • Violazione del principio della responsabilità singola – Ossessione per i 2pi primi2vi e troppi parametri • Sinonimo di ca-va proge&azione • I principi dell’OO non sono usa2 al meglio – Statement switch su ogge- • Meglio usare il polimorfismo – Rifiuto dell’ereditarietà – Classi alterna2ve con interfacce diverse • Sinonimo di ca-va proge&azione della gerarchia delle classi Tipi primi2vi public Class Car{ private int red, green, blue; public void paint(int red, int green, int blue){ this.red = red; this.green = green; this.blue = blue; } } public Class Car{ private Color color; public void paint(Color color){ this.color = color; } } Switch e polimorfismo public Money calculatePay(Employee e) throws InvalidEmployeeType{ switch(e.type){ case COMMISSIONED: return calculateCommissionedPay(e); case HOURLY: return calculateHourlyPay(e); case SALARIED: return calculateSalariedPay(e); default: throw new InvalidEmployeeType(e.type); } } public abstract class Employee { public abstract Money calculatePay(); } Ca-vo uso dell’ereditarietà • Le so&oclassi non usano i metodi e gli a&ribu2 della superclasse • Quota non riguarda Engineer – Dovrebbe essere solo parte di Salesman public abstract class Employee{ private int quota; public int getQuota(); ... } public class Salesman extends Employee{ ... } public class Engineer extends Employee{ ... public int getQuota(){ throw new NotSupportedException(); } } Alcuni errori comuni • Elemen2 che complicano la manutenzione del codice – Codice divergente • Una classe deve essere cambiata in diversi pun2 – Intervento urgente • Un singolo cambiamento richiede modifiche in diverse classi • Il codice con2ene elemen2 non necessari – Una classe non fa a sufficienza • Una classe non fornisce logica – Codice non u2lizzato o ridondante • Non è nulla di u2le Alcuni errori comuni • Alcune classi sono troppo accoppiate – Abuso di proprietà altrui • Responsabilità mal distribuite – In2mità non appropriata • Una classe dovrebbe conoscere il meno possibile delle altre classi – Catene di invocazioni • Accesso ai da2 troppo complesso Abuso di cara&eris2che altrui public class Customer{ private PhoneNumber mobilePhone; ... public String getMobilePhoneNumber(){ return “(” + mobilePhone.getAreaCode() + “)” + mobilePhone.getPrefix() + “-” + mobilePhone.getNumber(); } } public String getMobilePhoneNumber(){ return mobilePhone.toFormattedString(); } Catene di invocazioni • a.getB().getC().getD().getTheNeededData() • a.getTheNeededData() • Legge di Demeter – Parla solo con i tuoi amici più stre-
© Copyright 2024 ExpyDoc