Ho letto quasi tutte le domande contrassegnate da Law-of-Demeter. La mia domanda specifica non trova risposta in nessuna di queste altre domande, sebbene sia molto simile. Principalmente la mia domanda è quando hai un oggetto con strati di composizione, ma la necessità di recuperare i valori delle proprietà dai vari oggetti, come ottieni questo e perché prendere un approccio rispetto all'altro?Come funzionano la Legge di Demetra e la composizione con le collezioni?
Diciamo che dispone di un oggetto piuttosto standard composto da altri oggetti, in questo modo:
public class Customer {
private String name;
private ContactInfo primaryAddress;
private ContactInfo workAddress;
private Interests hobbies;
//Etc...
public getPrimaryAddress() { return primaryAddress; }
public getWorkAddress() { return workAddress; }
public getHobbies() { return hobbies; }
//Etc...
}
private ContactInfo {
private String phoneNumber;
private String emailAddress;
//Etc...
public getPhoneNumber() { return phoneNumber; }
public getEmailAddress() { return emailAddress; }
//Etc...
}
private Interests {
private List listOfInterests;
}
Il seguente sarebbe sia violare la legge di Demetra:
System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
Questo anche possa violare la legge di Demetra, penso (chiarimento?):
ContactInfo customerPrimaryAddress = customer.getPrimaryAddress();
System.out.println("Phone: " + customerPrimaryAddress.getPhoneNumber());
Quindi presumibilmente, tu ld quindi aggiungere un "getPrimaryPhoneNumber()" metodo per clienti:
public getPrimaryPhoneNumber() {
return primaryAddress.getPhoneNumber();
}
E poi semplicemente chiamare: System.out.println ("Telefono:" + customer.getPrimaryPhoneNumber());
Ma farlo nel tempo sembra che in realtà fornirebbe un sacco di problemi e lavorare contro l'intenzione della legge di Demetra. Rende il cliente classe in un enorme bagaglio di getter e setter che ha troppa conoscenza delle proprie classi interne. Ad esempio, sembra possibile che l'oggetto Cliente abbia un giorno diversi indirizzi (non solo un indirizzo "primario" e un indirizzo "di lavoro"). Forse anche la classe Customer avrà semplicemente una lista (o altra raccolta) di oggetti ContactInfo piuttosto che oggetti specifici ContactInfo con nome. In che modo continui a seguire la legge di Demetra? Sembrerebbe sconfiggere lo scopo dell'astrazione. Ad esempio, questo sembra ragionevole in un caso del genere in cui un cliente ha una lista di elementi ContactInfo:
Customer.getSomeParticularAddress(addressType).getPhoneNumber();
Questo mi sembra si può ottenere ancora più pazzo quando si pensa di alcune persone che hanno un telefono cellulare e un telefono fisso, e quindi ContactInfo deve avere una raccolta di numeri di telefono.
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
In questo caso, non solo ci riferiamo ad oggetti all'interno di oggetti all'interno di oggetti, ma abbiamo anche sapere quali sono le AddressType validi di e di PHONETYPE sono. Posso sicuramente vedere un problema con questo, ma non sono sicuro di come evitarlo. Soprattutto quando qualsiasi classe lo chiama, probabilmente sa che vogliono estrarre il numero di telefono "mobile" per l'indirizzo "primario" del cliente in questione.
Come potrebbe essere effettuato il refactoring per conformarsi alla legge di Demeter e perché ciò andrebbe bene?
Penso che si sta prendendo troppo alla lettera, è solo una linea guida per un eventuale codice di odori. Quello che stai facendo va bene. – Esailija
D'accordo con Esailija, la legge di demeter non ha realmente bisogno di essere applicata ai getter, sono troppo banali. Infatti, facendo ciò che suggerisci (Customer.getPrimaryPhoneNumber()) porterebbe al Cliente a conoscere gli interni di ContactInfo. Il vantaggio di avere oggetti tipo Composizione è che limiti chi deve sapere su ContactInfo, ad es. – Taylor
OK, vedo questo punto, ma nella mia mente ci saranno scenari non getter/setter per le cose all'interno di ContactInfo. Supponi di voler inviare via email al cliente da un link o un pulsante. Potresti scriverlo come customer.getSomeParticularContactInfo (addressType) .sendEmail() o customer.sendEmail() che poi (all'interno del cliente) chiama getSomeParticularContactInfo ("primary"). SendEmail(). Oppure ci sono altre opzioni come una classe manager che gestisce l'azione. L'esempio quindi non riguarda i getter o setter e mi confondo su come procedere per prendere decisioni di progettazione in quel contesto. –