Come trattare con Law of Demeter nella relazione prodotto-proprietario?

4

Desidero visualizzare il prodotto e la scheda prodotto contiene molte informazioni sul prodotto e sul proprietario. Come trattare con Law of Demeter in questo prodotto - relazione con il proprietario?

Nel controller attualmente ho:

Product product = productRepository.get(1);

E nel modello:

product.name
product.description
product.owner.name
product.owner.address

Ma le ultime due chiamate infrangono la legge di Demeter.

Quindi dovrei essere in classe getter di aggiunta del prodotto:

getOwnerName()
getOwnerAddress()

E nel modello:

product.name
product.description
product.ownerName
product.ownerAddress

Ma se ho, ad esempio, 10 informazioni sull'autore, devo fare fino a 10 gettoni aggiuntivi, che duplicano solo il codice.

Forse il modo migliore sarebbe nel controller:

Product product = productRepository.get(1);
Owner owner = ownerRepository.get(product.ownerId);

E nel modello:

product.name
product.description
owner.name
owner.address

Ma allora una tale struttura sarà coerente per un altro programmatore?

Come dovrebbe essere fatto nelle applicazioni professionali?

    
posta vovon 11.03.2018 - 10:54
fonte

4 risposte

4

La motivazione alla base di Law of Demeter (principio di conoscenza minima) è di evitare l'accoppiamento con i dettagli di implementazione interna di un componente / sottosistema software, non di limitare il numero di punti nella dichiarazione.

Quindi, è tempo di pensare all'architettura (nel senso del design di alto livello) della tua applicazione. Se sia Product che Owner fanno parte della "superficie", l'interfaccia (in senso lato) per un sottosistema - quindi scrivere product.owner.name va bene. (Almeno, fino a quando qualcosa ti costringe a ridisegnare la relazione tra il prodotto e il proprietario - ma, se questa possibilità è anche la pena di essere presa in considerazione è qualcosa che devi decidere per te stesso, quindi ignorerò che per gli scopi di questo risposta.)

Se l'operazione di accesso ai membri di secondo livello ottiene effettivamente qualcosa che dovrebbe essere davvero un dettaglio di implementazione del componente / sottosistema (qualcosa che potresti voler riorganizzare, sostituire con un'implementazione diversa, ecc.), allora hai una violazione di LoD. Soprattutto se la catena di chiamate si estende ulteriormente, dove si ottengono oggetti che sono dettagli di implementazione dei dettagli di implementazione.

    
risposta data 11.03.2018 - 12:49
fonte
3

La legge di Demetra non è una legge: è una linea guida. Usa un po 'di buon senso.

Se una proprietà è logicamente una proprietà del prodotto, rendila una proprietà, anche se è implementata internamente in modo diverso.

Ma il proprietario del prodotto è un oggetto a sé stante che è probabile che un utente del prodotto Calais sia interessato direttamente.

In questo caso, pubblica l'oggetto proprietario. In altri casi, usa il buon senso.

    
risposta data 11.03.2018 - 12:10
fonte
0

Anche se la legge di Demetra non è una legge immutabile, ed è giusto romperla in alcune situazioni, quello che stai facendo in particolare mi sembra un odore di codice.

Perché non annidare un modello per la visualizzazione di un proprietario all'interno del modello per la visualizzazione del prodotto? Invece del rendering del prodotto sia "product.owner.name" che "product.owner.address", il template proprietario sarebbe passato come "argomento di prodotto". Quindi, all'interno del modello proprietario, esegui il rendering "owner.name" e "owner.address".

Questo modello di proprietario può quindi anche essere riutilizzato in altri luoghi, dove è necessario visualizzare le informazioni del proprietario, quindi se i campi vengono aggiunti ai proprietari è sufficiente modificarlo in un unico posto invece di modificare il modello per tutto ciò che è un proprietario, quindi molto più conforme a principi come il Principio di Responsabilità Unica.

In definitiva suggerirei che tutte le viste / i modelli siano annidati nello stesso modo in cui sono gli oggetti dati. Ogni vista / modello dovrebbe corrispondere solo a un singolo oggetto, e se quell'oggetto contiene altri oggetti con i propri campi, allora avresti una vista / modello annidato per rendere quell'oggetto.

    
risposta data 12.03.2018 - 18:17
fonte
-2

Il codice UI non è esente dalla legge di Demeter, hai ragione a cercare una soluzione migliore.

Un modo possibile orientato agli oggetti, diretto, "LoD compliant" per costruire l'interfaccia utente è lasciare che gli oggetti si presentino . Questa è una soluzione piuttosto semplice, ma sfortunatamente è un argomento tabù per ragioni dogmatiche.

I vantaggi sono evidenti:

  • Nessuna violazione di incapsulamento
  • Nessuna violazione di LoD
  • Nessun indebolimento della coesione
  • Disaccoppiamento effettivo del codice UI da Business Objects

L'ultimo punto potrebbe richiedere alcuni chiarimenti. Nel codice UI tradizionale basato su getter / setter, tutto il codice dell'interfaccia utente di solito conosce gli oggetti business, quali "proprietà" hanno, come ottenerle dall'utente, come reimpostarle sugli oggetti business, ecc. porta a un accoppiamento stretto . Basta chiedere a te stesso, cosa succede se le proprietà cambiano nell'oggetto business? Se hai bisogno di modificare anche il codice dell'interfaccia utente, questo è un segno di accoppiamento stretto piuttosto ovvio.

Se il tuo oggetto si presenta comunque, il codice dell'interfaccia utente (pannelli, tabelle, pagine, ecc.) può rimanere completamente libero dalla conoscenza del business.

Gli oggetti business sapranno un po 'di più sull'interfaccia utente come nel modo "tradizionale" a strati, ma conosceranno solo cose astratte. Come ci sono tabelle, pannelli, ecc. Non dovrebbero assolutamente conoscere i dettagli su questi, come quali colori sono usati, quali tag HTML e così via.

    
risposta data 11.03.2018 - 20:12
fonte