Вопрос

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

Это плохо.

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

Это хорошо.

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

Это плохо.

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

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

Это было полезно?

Решение

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

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

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

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

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

" тестеры Mockist больше говорят о том, как избежать "крушения поезда" - цепочек методов стиля getThis (). getThat (). getTheOther (). Избегание цепочек методов также известно как следование Закону Деметры. В то время как цепочки методов - запах, противоположная проблема объектов среднего человека, раздутых методами пересылки, - также запах. (Я всегда чувствовал, что мне было бы удобнее с Законом Деметры, если бы он назывался Предложение Деметры .) & Quot;

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

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

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

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

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

int price = customer.getOrderPrice();

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top