La dura legge di Demetra
La legge di Demetra (Law of Demeter o LoD o Principle of Least Knowledge) è una regola alla base della programmazione ad oggetti che consiglia di far conoscere ad un dato oggetto il minor numero di informazioni riguardo la struttura o le proprietà degli altri oggetti.
Ad esempio la seguente classe viola questa regola:
class WordDocument {
private String title;
…
WordDocument(HtmlDocument htmlDocument){
this.title = htmlDocument.getTitle();
}
…
}
Mentre il seguente esempio la rispetta:
class WordDocument {
private String title;
…
WordDocument(String title){
this.title = title;
}
…
}
Perchè WordDocument deve conoscere HtmlDocument? Il vantaggio potrebbe essere quello di convertire facilmente un documento Word in uno Html, ma non è questo il caso perchè l’unica informazione che realmente serve è il titolo del documento. Gli svantaggi invece sono tanti:
- posso costruire un documento Word solo a partire da un documento html, qualcuno potrebbe suggerire l’inserimento di due costruttori nella classe, ma in tal caso assegnerei una responsabilità impropria a WordDocument, una soluzione potrebbe essere l’utilizzo del pattern Factory.
- non è chiaro all’utilizzatore della mia classe di cosa veramente abbia bisogno un documento word per essere inizializzato.
- la complessità nella creazione di test unitari in isolamento aumenta perchè abbiamo a che con un altro oggetto di cui potremmo non conoscere il comportamento e per avere un test in isolamento dovremmo ricorrere a oggetti mock, ammesso che HtmlDocument sia una interfaccia.
- il livello di accoppiamento nel codice aumenta e tutti noi sappiamo che non è cosa buona: vero?
Qualcuno potrebbe obiettare che questo esempio non è attendibile perchè troppo semplice. Ad esempio per la costruzione di un WordDocument potrei avere bisogno di altre informazioni:
class WordDocument {
private String title;
private String subtitle;
private String authorName;
private String authorSurname;
private String description;
private int pageNumber;
…
WordDocument(String title, String subtitle, String authorName, String authorSurname String description, int pageNumber){
this.title = title;
this.subtitle = subtitle;
this.authorName = authorName;
this.authorSurname = authorSurame;
this.description = description;
this.pagenumber = pagenumber;
}
…
}
E’ facile notare che il costruttore è cresciuto non poco e utilizzare una istanza di HtmlDocument avrebbe semplificato notevolmente il codice.
Una soluzione consigliata da Craig Larman nel libro “Applicare UML e pattern” è l’utilizzo delle “classi descrizione” che trai vari vantaggi hanno quello di ridurre informazioni ridondanti o ripetute, infatti il costruttore simile a quello di WordDocument potrebbe essere presente in HtmlDocument, quindi:
class DocumentInfo {
private String title;
private String subtitle;
private String authorName;
private String authorSurname;
private String description;
private int pageNumber;
…
DocumentInfo(String title, String subtitle, String authorName, String authorSurname String description, int pageNumber){
this.title = title;
this.subtitle = subtitle;
this.authorName = authorName;
this.authorSurname = authorSurame;
this.description = description;
this.pagenumber = pagenumber;
}
…
}
e WordDocument diventa:
class WordDocument {
private DocumentInfo documentInfo;
WordDocument(DocumentInfo documentInfo){
this.documentInfo = documentInfo;
}
}
Ora sono quasi soddisfatto, ma la legge di Demetra è ancora violata dall’utilizzo di authorName e authorSurname per descrivere le informazioni relative all’autore del documento. Questo proprio non va perchè stiamo rappresentando con dei semplici attributi una classe concettuale, cioè la classe Author:
class DocumentInfo {
…
DocumentInfo(String title, String subtitle, Author author, String description, int pageNumber){
this.title = title;
this.subtitle = subtitle;
this.author = author;
this.description = description;
this.pagenumber = pagenumber;
}
…
}
In questo caso la creazione di una classe porta al rispetto della legge di Demetra perchè al documento non interessa conoscere il nome e cognome dell’autore ma l’entità autore. Questo avviene perchè se nel mondo reale non pensiamo a una determinata classe concettuale X come a un numero o a un testo, allora probabilmente X è una classe concettuale, non un attributo (sempre grazie a Larman per questa linea guida).
E se ancora non avete capito bene la legge di Demetra pensate a questo:
“Se in un negozio comprate qualcosa e dovete pagare €20. Date al commesso €20 o gli date il portafogli e gli dite di prendere €20?”
Bibliografia:
- Clean Code Talks – Dependency Injection di Misko Havery
- Applied UML and Patterns di Craig Larman

Lascia una Risposta