Secondo la legge di Demeter, una classe è autorizzata a restituire uno dei suoi membri?

14

Ho tre domande riguardanti la legge di Demeter.

Oltre alle classi che sono state specificatamente designate per restituire oggetti, come le classi factory e builder, va bene che un metodo restituisca un oggetto, ad es. un oggetto detenuto da una delle proprietà della classe o che violerebbe la legge di demeter (1)? E se viola la legge di demeter, sarebbe importante se l'oggetto restituito fosse un oggetto immutabile che rappresenta un pezzo di dati e non contiene nient'altro che getter per questi dati (2a)? O è un tale ValueObject un anti-pattern in sé, perché tutto ciò che viene fatto con i dati in quella classe viene fatto al di fuori della classe (2b)?

In pseudo codice:

class A {}

class B {

    private A a;

    public A getA() {
        return this.a;
    }
}

class C {

    private B b;
    private X x;

    public void main() {
        // Is it okay for B.getA to exist?
        A a = this.b.getA();

        a.doSomething();

        x.doSomethingElse(a);
    }
}

Sospetto che la legge di Demeter vieta uno schema come quello sopra. Cosa posso fare per garantire che doSomethingElse() possa essere richiamato senza violare la legge (3)?

    
posta user2180613 18.06.2016 - 15:37
fonte

5 risposte

6

In molti linguaggi di programmazione, tutti i valori restituiti sono oggetti. Come altri hanno già detto, non essere in grado di usare i metodi degli oggetti restituiti ti costringe a non restituire mai nulla. Dovresti chiederti: "Quali sono le responsabilità delle classi A, B e C?" Questo è il motivo per cui l'uso di nomi di variabili metasintattiche come A, B e C sollecita sempre la risposta "dipende" perché non ci sono responsabilità ereditarie in questi termini.

Potresti esaminare Domain Driven Design, che ti darà un insieme più dettagliato di euristiche per ragionare su dove dovrebbe andare la funzionalità e su chi dovrebbe invocare cosa.

La tua seconda domanda riguardante gli oggetti immutabili parla della nozione di un oggetto valore rispetto a un oggetto Entity. in DDD, puoi passare oggetti di valore senza quasi nessuna restrizione. Questo non è vero per gli oggetti entità.

Il LOD semplicistico è espresso molto meglio in DDD come regole per accedere agli Aggregati . Nessun oggetto esterno dovrebbe contenere riferimenti a membri di aggregati. È necessario conservare solo un riferimento di root.

DDD a parte, almeno vuoi sviluppare i tuoi set di stereotipi per le tue classi che siano ragionevoli per il tuo dominio. Applica regole su quegli stereotipi mentre progetta il tuo sistema.

Ricorda inoltre sempre che tutte queste regole sono per gestire la complessità, non per ostacolare i muscoli posteriori.

    
risposta data 18.06.2016 - 19:15
fonte
5

According to Demeter's law, is a class allowed to return one of its members?

Sì, sicuramente lo è.

Diamo un'occhiata ai punti principali :

  • Ogni unità dovrebbe avere solo una conoscenza limitata delle altre unità: solo le unità "strettamente" correlate all'unità corrente.
  • Ogni unità dovrebbe parlare solo con i suoi amici; non parlare con estranei.
  • Parla solo con i tuoi amici più stretti.

Tutti e tre dei quali ti lasciano una domanda: Chi è un amico?

Quando decidi cosa restituire, The Law of Demeter o il principio di minima conoscenza (LoD) non impone di difendere dai programmatori che insistono nel violentarla. Si impone di non forzare i programmatori a violarlo.

Ottenere questi confusi è esattamente il motivo per cui così tanti pensano che un setter debba sempre restituire il nulla. No. È necessario consentire un modo per creare query (getter) che non modificano lo stato del sistema. Questa è la separazione della query del comando di base.

Questo significa che sei libero di approfondire una base di codice concatenando ciò che vuoi? No. Unire insieme solo ciò che doveva essere incatenato insieme. Altrimenti la catena potrebbe cambiare e improvvisamente le tue cose sono rotte. Questo è ciò che si intende per amici.

Le catene lunghe possono essere progettate per. Interfacce fluenti, iDSL, gran parte di Java8 e il buon vecchio StringBuilder hanno tutte lo scopo di creare catene lunghe. Non violano LoD perché tutto nella catena è pensato per lavorare insieme e ha promesso di continuare a lavorare insieme. Tu infrangi Demeter quando leghi insieme cose che non si sono mai sentite. Gli amici sono quelli che hanno promesso di far funzionare la catena. Amici degli amici no.

Apart from classes which were specifically appointed to return objects - such as factory and builder classes - is it okay for a method to return an object, e.g. an object held by one of the class's properties or would that violate the law of demeter (1)?

Questo crea solo un'opportunità per violare Demeter. Questa non è una violazione. Questo non è nemmeno necessariamente male.

And if it violates the law of demeter, would it matter if the object returned is an immutable object that represents a piece of data and contains nothing but getters for this data (2)?

Immutabile è buono ma irrilevante qui. Ottenere cose attraverso una catena più lunga non lo rende migliore. Ciò che lo rende migliore è separare il recupero dall'uso. Se stai usando, chiedi quello che ti serve come parametro. Non andare a caccia di esso scavando nel gettare di estranei.

In pseudo code:

I suspect that Demeter's law forbids a pattern such as the above. What can I do to ensure that doSomethingElse() can be called while not violating the law (3)?

Prima di parlare di x.doSomethingElse(a) comprendi che hai scritto in modo semplice

b.getA().doSomething()

Ora, LoD non è un esercizio di conteggio dei punti . Ma quando crei una catena stai dicendo che sai come ottenere un A (utilizzando B ) e sai come usare A . Bene, ora A e B farebbero meglio ad essere amici intimi perché li hai semplicemente accoppiati.

Se avessi appena chiesto qualcosa per consegnarti una cosa simile a A potresti usare A e non ti sarebbe importato da dove proviene e B potrebbe vivere una vita felice e libera dalla tua ossessione per ottenendo A da B .

Per quanto riguarda x.doSomethingElse(a) senza i dettagli di dove proviene x , LoD non ha nulla da dire a riguardo.

LoD può incoraggiare separare l'uso dalla costruzione . Ma farò notare che se trattate religiosamente ogni oggetto come non amichevole, sarete bloccati a scrivere codice in metodi statici. Puoi costruire un grafo di oggetti meravigliosamente complesso in questo modo, ma alla fine devi chiamare un metodo su di esso per far funzionare la cosa. Devi semplicemente decidere chi sono i tuoi amici. Non c'è modo di scappare da quello.

Quindi sì, una classe può restituire uno dei suoi membri sotto LoD. Quando lo fai dovresti chiarire se quel membro è amichevole con la tua classe, perché se non lo è, alcuni clienti potrebbero provare ad abbinarti a quel corso usando te per averlo prima di usarlo. Questo è importante perché ora ciò che ritorni deve sempre supportare quell'uso.

Ci sono molti casi in cui questo non è semplicemente un problema. Le raccolte possono ignorarlo semplicemente perché sono intese per essere amici di tutto ciò che le utilizza. Allo stesso modo gli oggetti valore sono amichevoli con tutti. Ma se hai scritto un indirizzo che convalida l'utilità che richiedeva un oggetto dipendente dal quale estrasse un indirizzo, piuttosto che chiedere l'indirizzo, beh, spero che il dipendente e l'indirizzo provengano entrambi dalla stessa libreria.

    
risposta data 18.06.2016 - 21:39
fonte
2

Apart from classes which were specifically appointed to return objects [...]

Non capisco bene questo argomento. Qualsiasi oggetto può restituire un oggetto come risultato di una chiamata di messaggio. Soprattutto se pensi in "tutto come oggetto".

Le classi, tuttavia, sono gli unici oggetti in grado di creare istantaneamente nuovi oggetti del loro tipo inviando loro il "nuovo" messaggio (o spesso sostituiti con una nuova parola chiave sulle più comuni lingue OOP)

Ad ogni modo, per quanto riguarda la tua domanda, sarei piuttosto sospettoso su un oggetto che restituisce una delle sue proprietà per poter essere usato altrove. Potrebbe essere che questo oggetto stia perdendo informazioni sul suo stato o sui suoi dettagli di implementazione.

E non vorresti che l'oggetto C fosse informato sui dettagli di implementazione di B. Questa è una dipendenza indesiderata dall'oggetto A dalla prospettiva dell'oggetto C.

Quindi potresti chiederti se C, conoscendo A, non sa troppo per il lavoro che deve fare, indipendentemente dal LOD.

Ci sono casi in cui ciò può essere legittimo, ad esempio chiedere un oggetto di raccolta per uno dei suoi elementi è appropriato e non infrangere alcuna regola Demeter. Chiedere a un oggetto Book per il suo oggetto SQLConnection d'altra parte è rischioso e dovrebbe essere evitato.

Il LOD esiste perché molti programmatori tendono a chiedere agli oggetti informazioni prima di eseguire un lavoro. LOD è lì per ricordarci che a volte (se non sempre) ci stiamo semplicemente complicando le cose, desiderando che i nostri oggetti facciano troppo. A volte dobbiamo solo chiedere ad un altro oggetto di fare il lavoro per noi. LOD è lì per farci riflettere due volte su dove posizioniamo il comportamento nei nostri oggetti.

    
risposta data 18.06.2016 - 18:32
fonte
0

Apart from classes which were specifically appointed to return objects - such as factory and builder classes - is it okay for a method to return an object?

Perché non dovrebbe essere? Sembra che tu suggerisca che è necessario segnalare ai tuoi colleghi programmatori che la classe è specificatamente pensata per restituire oggetti, o che non deve restituire alcun oggetto. Nelle lingue in cui tutto è un oggetto, questo limiterebbe strongmente le tue opzioni, poiché non saresti in grado di restituire nulla.

    
risposta data 18.06.2016 - 16:51
fonte
0

Dipende da cosa stai facendo. Se esponi un membro della tua classe, quando non è affare di nessuno che questo sia un membro della tua classe, o qual è il tipo di quel membro, è una cosa negativa. Se modifichi il tipo di quel membro e il tipo di funzione che restituisce il membro e tutti devono modificare il codice, è male.

D'altra parte, se l'interfaccia della tua classe afferma che fornirà un'istanza di una nota classe A, va bene. Se sei fortunato e puoi farlo fornendo un membro della tua classe, fai bene a te. Se hai cambiato quel membro da A a B, dovresti quindi riscrivere il metodo che restituisce un A, ovviamente ora dovrà costruirne uno e riempirlo con i dati disponibili, invece di restituire un solo liner un membro. L'interfaccia della tua classe sarebbe rimasta invariata.

    
risposta data 23.04.2017 - 16:42
fonte

Leggi altre domande sui tag