|
a risolvere tutti i problemi, ma mai nessuna di esse potra' porne uno. Einstein
|
|
| Home Page |
|
| Articoli |
|
| News |
|
| Forum |
|
| Classi |
|
|
|
|
|
[GRASP] Pattern High Cohesion
By
Luana Rinaldi
21 maggio 2008
|
 |
|
La coesione è una misura di quanto fortemente diverse responsabilità siano correlate e concentrate in un qualsiasi elemento del progetto, come ad esempio una classe o un insieme di esse. Una classe, ad esempio, dovrebbe svolgere compiti limitati, relativi ad una ben precisa responsabilità. Molto spesso invece si possono riscontrare classi che svolgono svariati compiti, non correlati tra loro: in questi casi, le classi prodotte presentano una bassa coesione e risultano difficili da isolare, complesse da riutilizzare e manutenere, e costituiscono elementi critici in caso di cambiamenti del codice. I problemi principali a cui vanno incontro questo genere di casi sono: - Scarsa riusabilità
- Scarsa comprensibilità
- Scarsa manutenibilità
Non esiste in generale una misura di quanto debba essere coesiva una classe, ma è comunque possibile individuare diversi livelli di coesione in base alla quantità e alla qualità di responsabilità delegate alla singola classe. I livelli sono: - Coincidental: moduli composti da molte parti non correlate tra loro;
- Logical: moduli composti da parti logicamente correlate tra loro, ma senza nessuna interazione tra di esse
- Temporal: elementi raggruppati in un modulo solo perchè vengono eseguiti tutti nel medesiomo periodo temporale;
- Procedural: moduli composti da componenti che svolgono un intero flusso di lavoro
- Communicational: elementi che operano sullo stesso input oppure producono lo stesso output;
- Sequential: le componenti sono organizzate in modo che l’output di una procedura costituisca l’input della successiva
- Informational: molte funzioni dello stesso modulo hanno accesso alla stessa struttura dati o risorsa che è nascosta attaverso il modulo stesso
- Functional: il modulo ha la responsabilità di una sola azione, o di raggiungere un solo obiettivo. Tutte le parti del modulo contribuiscono a questa funzione, e nessuna di essa è estranea all’obiettivo
Di quelli elencati, solo gli ultimi due possono essere definiti livelli di buna coesione, mentre il livello 6 può essere in alcuni casi accettabile. Passiamo ora alla definizione formale del Pattern High Cohesion: Nome: High Cohesion Problema: Come mantenere gli oggetti focalizzati, comprensibili e gestibili, sostenendo parallelamente un basso accoppiamento? Soluzione: Assegnazione delle responsabilità in modo tale che l’accoppiamento non necessario rimanga basso. Affrontiamo più nel dettaglio la specifica del pattern.
|
|
|
Problema: Come mantenere gli oggetti focalizzati, comprensibili e gestibili, sostenendo parallelamente un basso accoppiamento?
|
top
|
Come è già stato detto, high cohesion non è esattamente un pattern, ma più un principio di progettazione da tener presente nelle fasi iniziali. Ma una volta superata la fase di progettazione, è comunque necessario tenere sotto controllo il codice in modo da evitare la diminuzione di coesione durante l’implementazione. Di conseguenza, dovrebbero essere costantemente monitorati:
- Metodi: numero delle line of code ( non dovrebbero superare le 100)
- Classi: numero di metodi presenti ( non dovrebbero essere ne troppi ne troppo pochi)
- Metodi e Classi: nomi ( non dovrebbe essere difficile assegnare un nome)
- Metodi : passaggio di parametri (il comportamento di un metodo non dovrebbe dipendere dal tipo di parametri in input)
Se viene riscontrata anche soltanto una di queste situazioni, probabilmente l’elemento implementato presenta bassa coesione, quindi sarà necessario operare in modo da riportare l’elemento stesso ad un livello di coesione accettabile.
|
|
Soluzione
|
top
|
Purtroppo non esistono regole stabilite da seguire per poter rispettare i principi di coesione, ma è comunque seguire alcune linee guida di base per poter evitare situazioni come quelle descritte sopra.
Controllo Dimensioni: si possono definire delle dimensioni massime di ogni elemento da tener presente per evitare di assegnare ad esso troppe responsabilità. In generale, un metodo coesivo raramente supererà le 100 righe di codice, ed in media sarà di circa 40/50. Una classe coesiva difficilmente potrà avere più di 10/20 metodi. Un package coesivo non potrà consistere di 1000 classi.
Assegnazione Nomi: la difficoltà di assegnazione di un nome ad un elemento è in genere sintomo di scarsa coesività, in quanto può significare che quell’elemento ha troppe responsabilità. Ad esempio, raggruppare tutte le classi in un package utils costituisce un classico esempio di bassa coesione.
Numero Parametri: Normalmente il numero di parametri in ingresso ad un metodo dovrebbe essere in misura ridotta. Ancora più importante controllare, invece, è la gestione del comportamento del metodo a seconda del valore di un determinato parametri in input: questa situazione dovrebbe essere evitata progettando meglio l’intera classe (potrebbe costituire una soluzione l’applicazione del pattern Template Method, di cui si parlerà in seguito).
E’ necessario sottolineare, comunque, che queste linee guida andrebbero comunque seguite con criterio, ossia bilanciando il livello di coesione con l’esplosione di classi e metodi che svolgono responsabilità troppo limitate.
|
|
Conseguenze
|
top
|
La corretta applicazione di questo pattern comporta numerosi vantaggi in termini di manutenibilità e riusabilità del codice. Infatti, una classe altamente coesa svolge una ben determinata funzione, quindi in caso di errori si può facilmente localizzarne la causa; inoltre, in caso di necessità, la stessa classe può essere utilizzata come componente per svolgere altre funzioni che necessitano delle operazioni implementate nella classe stessa. Bisogna comunque bilanciare l’utilizzo di questo pattern con le esigenze di progetto, in modo da valutare gli eventuali impatti di un abbassamento di coesione per esigenze progettuali.
Implicitamente, comunque, il pattern high cohesion implica anche un basso accoppiamento, e quindi il rispetto del pattern Low Coupling.
|
|
Esempio
|
top
|
Supponiamo di dover creare una classe che si occupa della stampa di un report, passato in ingresso sottoforma di oggetto Java. Supponiamo inoltre che il sistema debba supportare diversi formati di stampa, come ad esempio PDF, DOC, XSL e così via. Si potrebbe prevedere una implementazione come la seguente:
public class PrintManager{ private final int PDF =0; private final int DOC = 1; private final int XLS = 2; private void print(Object o, int printType){ switch(printType){ case PDF: //doSomething break; case DOC: //doSomething break; case XLS: //doSomething break; default //doSomething break; } } }
Come si può vedere, questa classe presenta un unico metodo print() che accetta in ingresso una variabile da cui derivare il formato di stampa attraverso un blocco switch. Questa situazione è fortemente sconsigliata, in quanto si sta demandando ad un metodo di modificare il proprio comportamento in base al valore assunto dalla variabile printType. La situazione corretta potrebbe essere la seguente:
public class PrintManager{ private void printPDF(Object o){ //doSomething } private void printDOC(Object o){ //doSomething } private void printXLS(Object o){ //doSomething } }
Un’ulteriore raffinamento potrebbe essere fatto identificando le parti comuni dei tre metodi ( come ad esempio la formattazione delle variabili dell’oggetto) e inserire questa logica in un metodo comune o in una superclasse, utilizzando poi il pattern Template Method o la stessa ereditarietà per gestire i differenti formati.
|
|
Pattern Correlati
|
top
|
Patern Low Coupling (GRASP)
Pattern Template Method (GOF)
|
|
Conclusioni
|
top
|
In questo articolo abbiamo presentato il pattern High Cohesion. Nel prossimo articolo parleremo del pattern Controller.
|
|
Bibliografia
|
top
|
[1] Low Coupling Pattern di Ugo Landini
[2] Applying GRASP to Object Design - Creator GRASP Pattern - Who is responsible for creating a class? - Applying UML and Patterns
[3] Gamma, Erich. “Object Oriented Software Development based on ET++: Design Patterns, Classe Library, Tools.” Tesi di Dottorato, University of Zurich, Institut Fur Informatik, 1991.
[4] Gamma, Helm, Johnson, Vlissides. “Design Patterns: Elements of Reusable Object-Oriented Software”, Pearson Education Inc., 1995.
[5] Larman, Craig. “Applying UML and Patterns :An Introduction to Object-Oriented Analysis and Design and the Unified Process”, Pearson Education Inc., 2005.
[6] Object Management Group, 2003. UML 2.0 Superstructure Specification. www.uml.org.
|
|
|

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons
|
|
|