Связь, сплоченность и закон Деметры

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

Это плохо.

Решение было бы для класса, о котором вы знаете, по существу, предоставляя простые оболочки, которые делегируют ответственность объекту, с которым он связан.

Это хорошо.

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

Это плохо.

Действительно ли это приводит к снижению сплоченности? Это меньшее из двух зол?

Является ли это одной из тех серых областей развития, где вы можете обсудить, где проходит линия, или есть сильные, принципиальные способы принятия решения о том, где провести черту и какие критерии вы можете использовать для принятия этого решения?

Хотя немного не по теме, я настоятельно рекомендую Теда Фейзона «Программирование на основе событий: доведение событий до предела» связь. Он дает подробный анализ общих проблем со связью и дает хорошую систему измерения количества сцепления в данной системе.

Paul Sullivan 30.10.2011 16:13

При нарушении LoD, независимо от того, являются ли дополнительные связи "неподходящий" зависит от природы связанных классов: если они очень заметны (подумайте о строке, столбце, ячейке в реализации Excel), связь с ними не вызывает проблем, а LoD является чрезмерно ограничивающим. Точно так же, если рассматриваемые классы намеренно являются простыми классами данных, по сути, без поведения.

Lutz Prechelt 23.09.2014 18:31
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Принцип подстановки Лискова
Принцип подстановки Лискова
Принцип подстановки Лискова (LSP) - это принцип объектно-ориентированного программирования, который гласит, что объекты суперкласса должны иметь...
67
2
8 015
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

В ситуациях, когда кажется, что существует компромисс между связностью и сплоченностью, я бы, вероятно, спросил себя: «Если бы кто-то другой уже написал эту логику, и я искал в ней ошибку, куда бы я посмотрел в первую очередь?», И напишите код таким образом.

Если вы нарушаете Закон Деметры, имея

int price = customer.getOrder().getPrice();

решение состоит не в том, чтобы создавать getOrderPrice () и преобразовывать код в

int price = customer.getOrderPrice();

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

Ссылка «скажи, а не спрашивай» стоит того, чтобы ее прочитать. Спасибо!

Dave Jarvis 02.09.2009 08:13

«Говори, а не спрашивай» также приближает вас к абстракциям в предметной области (требования пользователя), а не к деталям реализации (дизайн или производные требования).

Fuhrmanator 08.08.2013 20:15

Я не знаю, действительно ли это снижает сплоченность.

Агрегация / композиция - это все о классе, использующем другие классы для выполнения контракта, который он предоставляет через свои общедоступные методы. Классу не нужно дублировать интерфейс связанных с ним объектов. Фактически он скрывает любые сведения об этих агрегированных классах от вызывающего метода.

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

Другими словами, каждый класс имеет одну или несколько зависимостей от других классов, однако это всегда зависимости только от указанного класса, а не от каких-либо объектов, возвращаемых из свойств / методов.

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

Bradley Mazurek 02.10.2008 20:38

Это также касается уровня / типа используемой абстракции. Клиент, по определению, должен иметь некоторую тесную связь с Заказом. Следовательно, сплоченность клиента не снижается с помощью customer.getOrderPrice (); рефакторинг. например: Клиент может использовать простую десятичную дробь в качестве orderPrice.

Ash 02.10.2008 21:02

Как это не снижает сплоченность? Это не связано с Заказчиком, это связано с Заказом. Вы просто демонстрируете это на уровне Заказчика. Когда это начинает снижать сплоченность? Вызывает ли customer.getOrderAddressStreet () снижение сплоченности? Может все серое ....

Bradley Mazurek 02.10.2008 21:31

В канонической ситуации Заказы создаются Клиентами. Заказ без Клиента недействителен. Если что-то связано с Заказом, это также связано с Клиентом, создавшим этот заказ. Клиент и Заказ работают вместе, чтобы обеспечить четко ограниченное поведение. Смотрите мой дополнительный ответ.

Ash 03.10.2008 09:51

Я думаю, вы могли неправильно понять, что означает сплоченность. Класс, который реализован в терминах нескольких других классов, не обязательно имеет низкую сплоченность, если он представляет ясную концепцию и имеет ясную цель. Например, у вас может быть class Person, который реализован в терминах классов Date (для даты рождения), Address и Education (список школ, в которые пошел человек). Вы можете предоставить обертки в Person для получения года рождения, последней школы, в которой человек учился, или штата, в котором он живет, чтобы не раскрывать тот факт, что Person реализован с точки зрения этих других классов. Это уменьшило бы сцепление, но сделало бы Person не менее связным.

Это серая зона. Эти принципы предназначены для того, чтобы помочь вам в вашей работе, если вы обнаружите, что работаете на них (то есть они мешают вам и / или вы обнаружите, что это слишком усложняет ваш код), тогда вы слишком сильно соответствуете и вам нужно отступить.

Сделайте так, чтобы это работало на вас, не работайте на это.

это хорошее описание Закона Деметры «Сделай так, чтобы он работал на тебя, не работай на него».

erhun 28.09.2015 16:01
Ответ принят как подходящий

Грэди Буч в "Объектно-ориентированном анализе и дизайне":

«Идея сплоченности также исходит из структурированного дизайна. Проще говоря, сплоченность измеряет степень связи между элементами одного модуля (и для объектно-ориентированного дизайна - отдельный класс или объект). Наименее желательная форма сплоченность - это случайная сплоченность, в которой совершенно не связанные между собой абстракции брошены в тот же класс или модуль. Например, рассмотрим класс, состоящий из абстракции собак и космических кораблей, поведение которых совершенно не связано. В наиболее желательной формой сплоченности является функциональная сплоченность, в которой элементы все классы или модули работают вместе, чтобы обеспечить некоторое строго ограниченное поведение. Таким образом, класс Dog является функционально связным, если его семантика охватывает поведение собаки, всей собаки и ничего, кроме собаки ".

Замените Dog на Customer в приведенном выше примере, и это может быть немного яснее. Таким образом, цель на самом деле состоит в том, чтобы стремиться к функциональной сплоченности и максимально уйти от случайной сплоченности. В зависимости от ваших абстракций это может быть просто или может потребоваться некоторый рефакторинг.

Обратите внимание, что сплоченность применима как к «модулю», так и к отдельному классу, то есть к группе классов, работающих вместе. Таким образом, в этом случае классы Customer и Order по-прежнему имеют приличную сплоченность, потому что у них есть сильные отношения, клиенты создают заказы, заказы принадлежат клиентам.

Мартин Фаулер говорит, что ему было бы удобнее назвать это «Предложением Деметры» (см. Статью Моки - это не заглушки):

«Тестировщики-имитаторы больше говорят об избежании« крушения поезда »- цепочек методов стиля getThis (). GetThat (). GetTheOther (). Избегание цепочек методов также известно как следование закону Деметры. Хотя цепочки методов - это запах, Противоположная проблема с объектами посредников, раздутыми методами пересылки, также является запахом (я всегда чувствовал, что мне было бы удобнее с Законом Деметры, если бы он назывался Предложение Деметры.) "

Это хорошо резюмирует то, откуда я пришел: совершенно приемлемо и часто необходимо иметь более низкий уровень сплоченности, чем может потребоваться строгое соблюдение «закона». Избегайте случайной сплоченности и стремитесь к функциональной сплоченности, но не зацикливайтесь на настройке там, где это необходимо, чтобы более естественно вписаться в абстракцию вашего дизайна.

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

Bradley Mazurek 03.10.2008 16:44

Безусловно, это хороший способ выразиться. Кстати, вы видели JQuery, цепочка вызовов методов 3+ уровня является обычным явлением. Хотя это может быть в другом контексте (более процедурном), кто-то из JQuery может сказать, что Java / C# / C++ будет иметь всевозможные вредные привычки, которые нужно «отучить»!

Ash 05.10.2008 06:13

Если я могу предложить вам добавить этот момент в свой пост (о том, что нарушение Закона Деметры - это нормально) ... прямо сейчас это лучший ответ, который я видел.

Bradley Mazurek 05.10.2008 22:21

Еще один источник, с которым я столкнулся. Найдите Demeter на следующей странице и включите его в свой ответ ... martinfowler.com/articles/mocksArentStubs.html

Bradley Mazurek 06.10.2008 06:55

Брэдли, готово, кстати, хорошая цитата. Надеюсь, это будет полезно и многим другим.

Ash 07.10.2008 15:28

Что касается последнего абзаца, разве он не должен быть «избегайте случайной сплоченности»?

Auron 07.10.2008 15:40

Другие вопросы по теме