2016-03-10 8 views
5

Lassen Sie uns mit Wikipedia starten:Was ist Demeter-Gesetz?

formal Mehr verlangt das Gesetz von Demeter für Funktionen, dass ein Verfahren m eines Objekts O nur die Methoden der folgenden Arten von Objekten aufrufen können:

  1. O selbst
  2. m-Parameter
  3. Alle Objekte erstellt/in m instanziiert
  4. O direkte Komponente Objekte
  5. eine globale Variable, mit dem O, im Rahmen von m

Regel 1:

public class ClassOne { 

    public void method1() { 
     method2(); 
    } 

    public void method2() { 

    } 
} 

Regel 2:

public class ClassOne { 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Regel 3:

public class ClassOne { 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Regel 4 (dank @juharr):

public class ClassOne { 

    private ClassTwo classTwo; 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Regel 5:

? 

mir jemand mit Regel 5 helfen?


Und impliziert das Gesetz von Demeter, dass die Verkettung schlecht ist?

User.getName().getLastName(); 

Dies führt zu einer hohen Kopplung.


Ist nicht "Sag, frag nicht" ein ähnliches Prinzip?

Also ist das alles? Habe ich etwas falsch? Wie können Sie Demeter-Gesetz befolgen?

+0

Ja, im Grunde "Demeter" kann gelesen werden, um zu sagen: Verkettung ist schlecht. Du bekommst nichts, um etwas daraus zu machen, etwas in der letzten Sache zu tun. – GhostCat

+2

Regel 4 ist, wenn 'ClassOne' ein privates Feld (Komponente) vom Typ' ClassTwo' hat, dann können Sie Methoden für dieses Feld von Ihrer Methode in 'ClassOne' aufrufen. – juharr

+0

@juharr Danke! – Anonymous

Antwort

3

"Tell nicht fragen" ist ein bisschen anders.

Demeter: bekomme nichts, um etwas daraus zu machen, etwas auf die letzte Sache zu tun.

TDA: nicht "Informationen" von einem anderen Objekt abrufen, um dann eine Entscheidung darüber zu treffen. Einfaches Beispiel:

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

gegen

if (someList.isEmpty()) { bla 

In beiden Fällen müssen Sie eine Methode auf ein anderes Objekt aufrufen; aber es gibt einen entscheidenden Unterschied: der erste Aufruf macht den "internen" Zustand dieses anderen Objekts für Sie sichtbar; worauf Sie dann eine Entscheidung treffen.Während in der "TDA" verbesserte zweite Version; Sie verlassen diese "Statusbewertung" innerhalb dieses anderen Objekts; wodurch die Kopplung irgendwie reduziert wird.

2

Die 5. ist schwer in C# oder Java darzustellen, da sie keine globalen Variablen unterstützen. In einem Entwurfsmuster, das im Prinzip ähnlich ist, könnten Sie jedoch z.B. eine Konfigurationsklasse, die global zugängliche statische Konfigurationswerte, wie (C#) nur enthält:

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

In diesem Fall (unter der Annahme, das Entwurfsmuster in jeder anderen Hinsicht akzeptabel war), würde das Gesetz von Demeter dies, weil es global zugänglich ist und so sein soll.

+0

Also sollte das Feld "MyConfigurationValue" nicht öffentlich sein? – Anonymous

+0

@Robiow Nicht in diesem Beispiel, da hier gezeigt wird, wie globale Konfigurationsinformationen bereitgestellt werden. Wir möchten jedoch nicht, dass andere Klassen sie versehentlich oder absichtlich ändern können. Wenn Sie sowohl das Lesen als auch das Modifizieren von Eigenschaften zulassen, ist es generell notwendig, ein Feld öffentlich zu machen (für diejenigen, die den "Property" -Ansatz bevorzugen) würde ich darauf hinweisen, dass Eigenschaften meist nur eine hinterhältige Möglichkeit sind, das alles zu sagen Mitgliedsvariablen sind privat, obwohl sie sich so verhalten, als wären sie öffentlich, durch Methoden, die Overhead hinter den Kulissen hinzufügen, um sie öffentlich zu machen. –

1

Ein Beispiel für Regel 5 wäre:

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

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

    public void method2() { 
    } 
} 

Aufzählungen im Grunde auf diese Weise arbeiten, und es ist in Ordnung, um Zugang zu Aufzählungen.


Ihr Beispiel:

user.getName().getLastName(); 

widerspricht offensichtlich die Gesetze, da das Objekt, das Sie Suche von „getName()“ wird nicht aufgeführt in eine der Kategorien fallen. Hinweis: das ist falsch, auch wenn Sie nicht Ketten Anrufe verwenden:

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

seit dem Objekt „name“ fallen immer noch nicht in eine der genannten Kategorien.

aber Dinge wie diese sind ok:

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

Warum dies erlaubt ist? Weil Sie jedes Mal entweder dasselbe Objekt (den reportBuilder) oder jedes Mal ein neues Objekt erhalten, wenn der Builder als unveränderlich implementiert ist. Wie auch immer, es fällt in Gesetz 2 oder 3, also ist es in jedem Fall in Ordnung.


Ihre dritte Frage ist "wie man gehorcht". Nun, das ist eine komplexe Frage, aber denken Sie darüber nach, welche Methoden eigentlich durch die Gesetze verboten sind!

Setzen Sie einfach die Gesetze ins Negative: Wir sollten keine Methoden für Objekte aufrufen, die bereits dort sind (weil neue Objekte ausgenommen sind), und sind nicht mein Objekt oder Felder meines Objekts oder meine Parameter. So dass Objekte, die in den Bereichen andere Objekte sind verlassen!

Also im Grunde bedeutet das, dass Sie nicht in der Lage sein sollten, Zugriff auf Objekte zu bekommen, die nicht Sie sind, nicht in Ihren Feldern und nicht direkte Parameter. Was ich als "no getters" zusammenfassen würde!