Свободные интерфейсы нарушают Закон Деметры? - PullRequest
56 голосов
/ 16 сентября 2008

Статья в Википедии о Закон Деметры гласит:

Закон можно сформулировать просто как «используйте только одну точку».

Однако простой пример свободного интерфейса может выглядеть так:

static void Main(string[] args)
{
   new ZRLabs.Yael.Pipeline("cat.jpg")
        .Rotate(90)
        .Watermark("Monkey")
        .RoundCorners(100, Color.Bisque)
        .Save("test.png");
}

Так это идет вместе?

Ответы [ 6 ]

75 голосов
/ 16 сентября 2008

Ну, краткое определение закона слишком сильно его укорачивает. Настоящий «закон» (на самом деле совет по хорошему дизайну API) в основном гласит: Доступ только к объектам, которые вы создали сами или были переданы вам в качестве аргумента. Не обращайтесь к объектам косвенно через другие объекты. Методы плавных интерфейсов часто возвращают сам объект, поэтому они не нарушают закон, если вы снова используете объект. Другие методы создают объекты для вас, так что никаких нарушений тоже нет.

Также обратите внимание, что «закон» - это только совет по передовой практике для «классических» API. Свободные интерфейсы представляют собой совершенно другой подход к разработке API и не могут быть оценены с помощью закона Деметры.

24 голосов
/ 16 сентября 2008

Не обязательно. «Используйте только одну точку» - неточное изложение Закона Деметры.

Закон Деметры не рекомендует использовать несколько точек, когда каждая точка представляет результат другого объекта, например ::10000

  • Первая точка - это метод, вызываемый из ObjectA, возвращающий объект типа ObjectB
  • Следующая точка - метод, доступный только в ObjectB, возвращающий объект типа ObjectC
  • Следующая точка - это свойство, доступное только в ObjectC
  • до бесконечности

Однако, по крайней мере, на мой взгляд, закон Деметры не нарушается, если возвращаемый объект каждой точки все еще имеет тот же тип, что и исходный вызывающий объект:

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

В приведенном выше примере оба FindAll () и Sort () возвращают объект того же типа, что и исходный список. Закон Деметры не нарушается: в списке разговаривали только его ближайшие друзья.

При этом не все свободно взаимодействующие интерфейсы нарушают Закон Деметры, лишь бы они возвращали тот же тип, что и их вызывающая сторона.

8 голосов
/ 16 сентября 2008

Да, хотя вы должны применить некоторый прагматизм к ситуации. Я всегда принимаю Закон Деметры как правило, а не правило.

Конечно, вы можете избежать следующего:

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

возможно заменить на:

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

Поскольку многие из нас используют ORM, который обычно представляет весь домен в виде графа объектов, возможно, было бы целесообразно определить приемлемую «область видимости» для конкретного объекта. Возможно, нам следует принять закон Деметры, чтобы предположить, что вы не должны отображать весь график как достижимый.

7 голосов
/ 16 сентября 2008

Суть закона Деметера заключается в том, что, учитывая объектную ссылку или класс, вы должны избегать доступа к свойствам класса, который находится на расстоянии более одного дочернего свойства или метода, поскольку это будет тесно связывать два класса, которые могут быть непреднамеренными и может вызвать проблемы с ремонтопригодностью.

Свободные интерфейсы являются приемлемым исключением из закона, поскольку они означают, что как минимум несколько тесно связаны, так как все свойства и методы являются терминами мини-языка, которые составлены вместе для формирования функциональные предложения.

6 голосов
/ 24 ноября 2010

1) Это не нарушает его вообще.

Код эквивалентен

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) Как говорит добрый старик Фил Хаак: Закон Деметры - не упражнение по подсчету точек

1 голос
/ 20 марта 2010

Нет проблем с вашим примером. В конце концов, вы вращаетесь, ставите водяные знаки и т.д. ... всегда одно и то же изображение. Я полагаю, что вы все время общаетесь с объектом Pipeline, поэтому, если ваш код зависит только от класса Pipeline, вы не нарушаете LoD.

...