2016-03-10 21 views
5

Zacznijmy Wikipedia:Co to jest prawo Demeter?

Bardziej formalnie, Prawo Demeter dla funkcji wymaga, aby metoda m obiektu O może powoływać się tylko metody następujących rodzajów obiektów:

  1. sama O
  2. parametrów m
  3. Wszystkie obiekty utworzone/wystąpienia wewnątrz m
  4. bezpośredni komponent
  5. O za obiekty
  6. zmienną globalną, dostępną przez O, w zakresie m

Zasada 1:

public class ClassOne { 

    public void method1() { 
     method2(); 
    } 

    public void method2() { 

    } 
} 

Zasada 2:

public class ClassOne { 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Reguła 3:

public class ClassOne { 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Zasada 4 (dzięki @juharr):

public class ClassOne { 

    private ClassTwo classTwo; 

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

class ClassTwo { 

    public void method2() { 

    } 
} 

Zasada 5:

? 

Czy ktoś może mi pomóc z reguły 5?


A czy prawo Demeter nie sugeruje, że łańcuchy są złe?

User.getName().getLastName(); 

Prowadzi to do wysokiego sprzężenia.


Czy nie "powiedz, nie pytaj" o podobną zasadę?

Czy to wszystko? Czy myliłem się co do czegoś? Jak możesz przestrzegać Prawa Demeter?

+0

Tak, w zasadzie "demeter" można przeczytać, aby powiedzieć: łańcuchowanie jest złe. Nie dostaniesz czegoś, aby coś z tego zrobić, żeby zrobić coś na ostatnią rzecz. – GhostCat

+2

Reguła 4 jest taka, że ​​'ClassOne' ma prywatne pole (komponent) typu' ClassTwo', wtedy możesz wywołać metody na tym polu ze swojej metody w 'ClassOne'. – juharr

+0

@juharr Dzięki! – Anonymous

Odpowiedz

3

"Powiedz, nie pytaj" jest nieco inny.

Demeter: nie dostaniesz czegoś, aby coś z tego zrobić, żeby zrobić coś na ostatnią rzecz.

TDA: nie pobieraj "informacji" z innego obiektu, aby podjąć decyzję. Prosty przykład:

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

vs.

if (someList.isEmpty()) { bla 

W obu przypadkach dzwonisz metodę na jakiegoś innego przedmiotu; ale jest kluczowa różnica: pierwsze wezwanie ujawnia ci "wewnętrzny" stan tego innego obiektu; na którym następnie podejmujecie decyzję.Natomiast w "TDA" poprawiono drugą wersję; pozostawiasz tę "ocenę statusu" w obrębie tego innego obiektu; w ten sposób redukując sprzężenie.

2

Piąty jest trudny do reprezentowania w języku C# lub Java, ponieważ nie obsługuje on technicznych zmiennych globalnych. Jednak w zasadzie podobnej co do zasady możesz mieć np. klasa konfiguracji, która zawiera tylko globalnie dostępnych statycznych wartości konfiguracyjne, takie jak (C#):

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

W tym przypadku (zakładając, że wzorzec projektowy był dopuszczalny we wszystkich innych sposobów), ustawa Demeter Pozwoliłoby to, ponieważ jest globalnie dostępny i taki właśnie jest.

+0

Czy pole "MojaKonfiguracja" nie powinno być publiczne? – Anonymous

+0

@Robiow Nie w tym przykładzie, ponieważ pokazuje, jak dostarczyć informacje o konfiguracji w sposób globalny, ale nie chcemy, aby inne klasy mogły to zmienić, przez przypadek lub celowo. Zasadniczo, gdy pozwalasz zarówno na czytanie, jak i modyfikowanie właściwości, upublicznianie pola jest konieczne (dla tych, którzy preferują podejście "własnościowe", wskażę, że właściwości są przeważnie tylko podstępnym sposobem, aby móc powiedzieć, że wszystkie zmienne składowe są prywatne, mimo że działają tak, jakby były publiczne, za pomocą metod, które dodają dodatkowe informacje, aby były upubliczniane). –

1

Przykładem 5 regułą byłoby:

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

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

    public void method2() { 
    } 
} 

wyliczenia zasadzie działa w ten sposób, i to jest ok, aby teksty stałe dostępowych.


Twój przykład:

user.getName().getLastName(); 

oczywiście sprzeczne przepisy ustawowe, ponieważ obiekt można uzyskać z „getName()” nie należą do żadnej z wymienionych kategorii. Uwaga: to jest złe, nawet jeśli nie używasz łańcuch połączeń:

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

od obiektu „nazwa” jeszcze nie należą do żadnej z wymienionych kategorii.

Jednak takie rzeczy są w porządku:

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

Dlaczego jest to dozwolone? Ponieważ albo za każdym razem otrzymujesz ten sam obiekt (ReportBuilder), albo może za każdym razem nowy obiekt, jeśli budowniczy jest zaimplementowany jako niezmienny. Tak czy inaczej, wchodzi w zakres prawa 2 lub 3, więc jest ok.


Twoje trzecie pytanie brzmi "jak być posłusznym". Cóż, jest to skomplikowane pytanie, ale aby zacząć, zastanów się, jakie metody są faktycznie zakazane przez prawa!

Po prostu ustaw prawa na negatywne: Nie powinniśmy wywoływać metod na obiektach, które już tam są (ponieważ nowe obiekty są wyłączone) i nie są moim obiektem, polami mojego obiektu ani moimi parametrami. Tak więc pozostawia obiekty, które znajdują się w polach innych obiektów!

Oznacza to, że nie powinno być możliwe "uzyskanie" dostępu do obiektów, które nie są użytkownikami, a nie na polach, a nie bezpośrednie parametry. Które chciałbym streścić jako "nie pobiera"!