Это хороший пример Закона Деметры?

#java #oop #decoupling #design-principles #law-of-demeter

#java #ооп #развязка #принципы проектирования #закон Деметры

Вопрос:

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

Если у нас есть классная доска, и у нас есть игровые фигуры на нашем игровом поле, и, например, мы хотим выяснить, какие фигуры переместились, интуитивно понятным способом выяснить это было бы написать что-то вроде:

 Board.getGamePiece(p).getMovement();
 

Но это нарушает Закон Деметры. Таким образом, мы делегируем эту задачу методу getMovement, просто написав:

 Board.getMovement(p);
 

Правильно ли я понял и есть ли какие-либо ошибки в моем объяснении? Я немного не уверен в том, как использовать здесь термин «делегировать», правильно ли он используется в моем примере?

Комментарии:

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

Ответ №1:

Я думаю, вы поняли идею, но я не уверен, действительно ли ваш пример имеет смысл. В контексте настольной игры для доски сложно не беспокоиться о возможных движениях! (Поэтому применение Demeter здесь не имело бы смысла, поскольку, возможно, плата уже имеет доступ к классу Movement).

Ответ №2:

Я правильно понял Закон Деметры

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

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

Board.getGamePiece(p).getMovement();

против

Board.getMovement(p);

Это мое мнение, но, тогда, любой комментарий к этим строкам с точки зрения LoD — это мнение, и если кто-то пытается сказать вам, что это не так, они ошибаются 🙂

Они, в смысле LoD, полностью равны, и этот код (любая версия) полностью в порядке.

Дело в том, что оба подразумевают, что у вас есть представление о том, что существует такая вещь, как игровая фигура, и что фигуры могут двигаться. Обе строки кода также возвращают a Movement в некотором роде или форме, так что в любом случае этот код не просто знает, что «игровые фигуры существуют» и «они могут двигаться», но также «и вот как выглядит ход и как с ним взаимодействовать».

Вы ничего не выиграли, написав board.getMovement(p) .

Удалите эти туманные понятия, и вы начнете что-то понимать. Если бы вы написали board.advance() как метод, который применяет события на 1 ход, запрашивая у каждой фигуры движение, которое она хочет совершить, затем перемещая все фигуры и обрабатывая, например, что некоторые фигуры получили повреждения, то теперь у вас значительно меньше концепций: запущенный код board.advance() знает, что естьдоска, и что есть такая вещь, как повороты, и что вы можете продвинуться на один ход.

Коду не нужно знать, что части существуют или что они могут перемещаться.

Перевод ‘LoD’ в java в виде любого кода, который выглядит как: a.method1().method2() обязательно является разрывом LoD, ну, не стесняйтесь это делать. Однако, если вы немного перепутаете это и в итоге получите:

  1. a.method1().method2() нарушает LoD.
  2. Нарушение LoD — это плохой стиль кода, который затрудняет поддержку кода.
  3. Таким образом, a.method1().method2() это плохой код.

Тогда вы где-то напутали. Это не так; строгое применение этого принципа приведет к дублированию тонны кода и добавит БОЛЬШЕ зависимостей от уровня программиста (теперь код board должен знать гораздо больше о том, что могут делать части, чем если бы вы этого не делали).

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

В конце концов, цель состоит в том, чтобы написать поддерживаемый код. Это намного сложнее, чем пытаться применить некоторые заученные понятия, такие как «избегать a.x().y() «. Программирование — это сложно.