2016-03-10 9 views
5

Cominciamo con Wikipedia:Che cos'è Law of Demeter?

Più formalmente, la Legge di Demetra per le funzioni è necessario che un metodo m di un oggetto O può invocare solo i metodi dei seguenti tipi di oggetti:

  1. O si
  2. parametri di m
  3. Tutti gli oggetti creati/istanziati all'interno m
  4. componente diretta
  5. di O oggetti
  6. Una variabile globale, accessibile da O, nell'area di m

Regola 1:

public class ClassOne { 

    public void method1() { 
     method2(); 
    } 

    public void method2() { 

    } 
} 

Regola 2:

public class ClassOne { 

    public void method1(ClassTwo classTwo) { 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

Regola 3:

public class ClassOne { 

    public void method1() { 
     ClassTwo classTwo = new ClassTwo(); 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

regola 4 (grazie @juharr):

public class ClassOne { 

    private ClassTwo classTwo; 

    public void method1() { 
     classTwo = new ClassTwo(); 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

Regola 5:

? 

qualcuno mi può aiutare con l'articolo 5?


E la legge di Demetra non implica che il concatenamento è cattivo?

User.getName().getLastName(); 

Ciò comporta un accoppiamento elevato.


"Non dire, non chiedere" un principio simile?

Quindi è tutto? Mi sbaglio qualcosa? Come puoi obbedire alla Legge di Demetra?

+0

Sì, fondamentalmente "demeter" può essere letto per dire: il concatenamento è cattivo. Non ottieni qualcosa per ottenere qualcosa da quello per fare qualcosa sull'ultima cosa. – GhostCat

+2

La regola 4 è se 'ClassOne' ha un campo privato (componente) di tipo' ClassTwo', quindi puoi chiamare i metodi su quel campo dal tuo metodo in 'ClassOne'. – juharr

+0

@juharr Grazie! – Anonymous

risposta

3

"Dillo non chiedere" è un po 'diverso.

Demetra: non ottenere qualcosa da cui ottenere qualcosa per fare qualcosa sull'ultima cosa.

TDA: non recuperare "informazioni" da un altro oggetto per poi prendere una decisione in merito. Semplice esempio:

if (someList.size() == 0) { bla 

vs.

if (someList.isEmpty()) { bla 

In entrambi i casi si chiama un metodo su un altro oggetto; ma c'è una differenza fondamentale: la prima chiamata espone lo stato "interno" di quell'altro oggetto a te; su cui poi prendi una decisione.Considerando che, nel "TDA" migliorato seconda versione; lasci quella "valutazione dello stato" all'interno di quell'altro oggetto; quindi in qualche modo riducendo l'accoppiamento.

2

Il quinto è difficile da rappresentare in C# o Java, poiché non supportano tecnicamente le variabili globali. Tuttavia, in un modello di progettazione che è simile in linea di principio, potresti avere ad es. una classe di configurazione che contiene solo valori di configurazione statica globalmente accessibili, quali (C#):

internal class MyConfiguration 
{ 
    private static String MyConfigurationValue; // set in constructor 
    MyConfiguration(){ MyConfigurationValue = DoSomethingToLoadValue(); } 
    public static String GetMyConfigurationValue(){ return MyConfigurationValue; } 
} 

In questo caso (supponendo che il modello di progettazione era accettabile in tutti gli altri modi), la legge di Demetra permetterebbe questo, dal momento che è globalmente accessibile e destinato a essere così.

+0

Quindi il campo "MyConfigurationValue" non dovrebbe essere pubblico? – Anonymous

+0

@Robiow Non in questo esempio, poiché mostra come fornire le informazioni di configurazione in modo globale, ma non vogliamo che altre classi possano modificarle, accidentalmente o di proposito. In genere, quando si consente sia la lettura che la modifica delle proprietà, è necessario rendere pubblico un campo (per coloro che preferiscono l'approccio "proprietà", sottolineo che le proprietà sono per lo più solo un modo subdolo per poter dire che tutto le variabili membro sono private, anche se si comportano come se fossero pubbliche, attraverso metodi che aggiungono un sovraccarico dietro le quinte per renderle pubbliche). –

1

Un esempio per Regola 5 sarebbe:

public class ClassOne { 
    public void method1() { 
     classTwo.STATIC_INSTANCE.method2(); 
    } 
} 

class ClassTwo { 
    public static final ClassTwo STATIC_INSTANCE = ...; 

    public void method2() { 
    } 
} 

Enums fondamentalmente funziona in questo modo, ed è ok per enumerazioni di accesso.


Il vostro esempio:

user.getName().getLastName(); 

contraddice ovviamente le disposizioni legislative, dal momento che l'oggetto che si ottiene da "getName()" non cadere in nessuna delle categorie elencate. Nota: questo è sbagliato, anche se non si utilizza catene di chiamate:

Name name = user.getName(); 
name.getLastName(); // <- this is still wrong 

dal momento che il "nome" oggetto ancora non cadere in nessuna delle categorie elencate.

Tuttavia le cose come questa sono ok:

reportBuilder.withMargin(5).withFooter(10) 
    .withBorder(Color.black).build(); 

perché è questo permesso? Perché ogni volta ottieni lo stesso oggetto (il ReportBuilder), o forse un nuovo oggetto ogni volta se il costruttore è implementato come immutabile. Ad ogni modo, cade in legge 2 o 3, quindi va bene in entrambi i casi.


La terza domanda è "come obbedire". Bene, questa è una domanda complessa, ma per iniziare, pensa a che tipo di metodi sono effettivamente proibiti dalle leggi!

Basta mettere le leggi in negativo: non dovremmo chiamare metodi su oggetti che sono già lì (perché i nuovi oggetti sono esenti), e non sono il mio oggetto, né i campi del mio oggetto, né i miei parametri. In modo che lascia gli oggetti che sono nei campi di altri oggetti!

Quindi in pratica ciò significa che non si dovrebbe essere in grado di "ottenere" l'accesso a oggetti che non sono voi, non nei vostri campi e non parametri diretti. Che vorrei riassumere come "no getters"!