#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, ну, не стесняйтесь это делать. Однако, если вы немного перепутаете это и в итоге получите:
a.method1().method2()
нарушает LoD.- Нарушение LoD — это плохой стиль кода, который затрудняет поддержку кода.
- Таким образом,
a.method1().method2()
это плохой код.
Тогда вы где-то напутали. Это не так; строгое применение этого принципа приведет к дублированию тонны кода и добавит БОЛЬШЕ зависимостей от уровня программиста (теперь код board
должен знать гораздо больше о том, что могут делать части, чем если бы вы этого не делали).
Это подводит нас к еще одному уроку о таких туманных рекомендациях по стилю: они почти всегда находятся в прямой конкуренции. Если вы попытаетесь «оптимизировать» для LoD, вы, скорее всего, нарушите множество других правил, таких как DRY.
В конце концов, цель состоит в том, чтобы написать поддерживаемый код. Это намного сложнее, чем пытаться применить некоторые заученные понятия, такие как «избегать a.x().y()
«. Программирование — это сложно.