Czy płynne interfejsy łamią prawo Demeter?

Artykuł Wikipedii o prawie Demeter mówi:

Prawo można określić po prostu jako "użyj tylko jednej kropki".

Jednak prosty przykład z płynnego interfejsu może wyglądać tak:

static void Main(string[] args)
{
   new ZRLabs.Yael.Pipeline("cat.jpg")
        .Rotate(90)
        .Watermark("Monkey")
        .RoundCorners(100, Color.Bisque)
        .Save("test.png");
}
Więc to idzie w parze?
Author: Chris Jester-Young, 2008-09-16

6 answers

Cóż, krótka definicja prawa skraca go zbytnio. Prawdziwe "prawo" (w rzeczywistości porady na temat dobrego projektowania API) w zasadzie mówi: tylko dostęp do obiektów, które stworzyłeś samodzielnie, lub zostały przekazane Ci jako argument. Nie uzyskuj dostępu do obiektów pośrednio poprzez inne obiekty. Metody płynnych interfejsów często zwracają sam obiekt, więc nie naruszają prawa, jeśli ponownie użyjesz obiektu. Inne metody tworzą obiekty dla ciebie, więc nie ma naruszenia.

Zauważ również, że "prawo" to tylko porady dotyczące najlepszych praktyk dla" klasycznych " interfejsów API. Interfejsy Fluent są zupełnie innym podejściem do projektowania API i nie mogą być oceniane z Prawem Demeter.

 73
Author: Sebastian Rittau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-29 21:09:48

Niekoniecznie. "Użyj tylko jednej kropki" jest niedokładnym podsumowaniem prawa Demetera.

Prawo Demeter zniechęca do używania wielu kropek, gdy każda kropka reprezentuje wynik innego obiektu, np.:

  • Pierwsza kropka jest metodą wywoływaną z ObjectA, zwracającą obiekt typu ObjectB
  • Next dot jest metodą dostępną tylko w ObjectB, zwracającą obiekt typu ObjectC
  • Następna kropka jest właściwością dostępną tylko w ObjectC
  • ad infinitum

Jednak, przynajmniej moim zdaniem, prawo Demeter nie jest naruszone, jeśli obiekt return każdej kropki jest nadal tego samego typu co oryginalny wywołujący:

var List<SomeObj> list = new List<SomeObj>();
//initialize data here
return list.FindAll( i => i == someValue ).Sort( i1, i2 => i2 > i1).ToArray();

W powyższym przykładzie zarówno FindAll () jak i Sort () zwracają ten sam typ obiektu co oryginalna lista. Prawo Demeter nie jest naruszone: lista rozmawiała tylko z najbliższymi przyjaciółmi.

To powiedziane Nie wszystkie płynne interfejsy łamią prawo Demeter, tak długo, jak wrócą ten sam typ co ich rozmówca.

 23
Author: Jon Limjap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 22:28:00

Tak, chociaż musisz zastosować trochę pragmatyzmu w tej sytuacji. Zawsze traktuję prawo Demeter jako wskazówkę, a nie regułę.

Z pewnością możesz chcieć uniknąć następujących rzeczy:

CurrentCustomer.Orders[0].Manufacturer.Address.Email(text);

Być może zastąpić przez:

CurrentCustomer.Orders[0].EmailManufacturer(text);

Ponieważ Więcej z nas używa ORM, który ogólnie przedstawia całą domenę jako wykres obiektowy, może być pomysłem zdefiniowanie akceptowalnego "zakresu" dla określonego obiektu. Może powinniśmy przyjąć prawo demeter, aby zasugerować, że nie powinieneś mapować cały wykres jako osiągalny.

 8
Author: Quibblesome,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 22:23:36

Duch prawa Demetera polega na tym, że biorąc pod uwagę odniesienie do obiektu lub klasy, powinieneś unikać dostępu do właściwości klasy, która jest oddalona od siebie o więcej niż jedną pod-właściwość lub metodę, ponieważ będzie to ściśle łączyć dwie klasy, co może być niezamierzone i może powodować problemy z konserwacją.

Fluent interfaces są akceptowalnym wyjątkiem od prawa, ponieważ są oznaczało być przynajmniej nieco ściśle powiązane, ponieważ wszystkie właściwości i metody są warunkami mini-język, który tworzą razem funkcjonalne zdania.

 6
Author: Mark Cidade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-29 06:06:22

1) w ogóle go nie narusza.

Kod jest równoważny

var a = new ZRLabs.Yael.Pipeline("cat.jpg");
a = a.Rotate(90);
a = a.Watermark("Monkey");
a = a.RoundCorners(100, Color.Bisque);
a = a.Save("test.png");

2) Jak mówi stary dobry Phil Haack: prawo Demeter nie jest ćwiczeniem liczenia kropek

 6
Author: Andrei Rînea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-24 16:52:01

Nie ma problemu z twoim przykładem. W końcu obracasz się, dodajesz znaki wodne itp... zawsze ten sam obraz. Wierzę, że cały czas rozmawiasz z obiektem potoku, więc tak długo, jak Twój kod zależy tylko od klasy potoku, nie naruszasz LoD.

 1
Author: Peter Perháč,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-20 09:57:56