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

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

Плохо.

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

Это хорошо.

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

Плохо.

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

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

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

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

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

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

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

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

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

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

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

решение заключается не в создании getOrderPrice () и преобразовании кода в

 int price = customer.getOrderPrice(); 

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

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

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

Заставьте это работать для вас, не работайте для этого.

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

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

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

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

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

Давайте будем гением компьютера.