Закон Деметры (или принцип минимальной зависимости) — это принцип, который используется в объектно-ориентированном программировании (ООП) для повышения гибкости и упрощения кода. Он направлен на снижение связности компонентов системы и предотвращение слишком глубоких или сложных зависимостей между объектами. Это помогает избежать того, чтобы изменения в одном месте кода приводили к необходимости изменять другие части системы.
Основная идея закона Деметры
Закон Деметры можно сформулировать следующим образом:
«Объект должен взаимодействовать только с теми объектами, которые являются его непосредственными зависимостями.»
Он предлагает ограничить количество связей между объектами, уменьшив количество вызовов методов объектов, которые находятся на большом расстоянии от текущего объекта.
Проще говоря, объект не должен «знать» о внутренностях других объектов, с которыми он не является напрямую связан, и, тем более, не должен их изменять. Он должен взаимодействовать только с теми объектами, которые являются его непосредственными партнерами.
Применение закона Деметры
Закон Деметры накладывает несколько ограничений на взаимодействие между объектами:
Объект не должен вызывать методы объектов, которые возвращаются как результаты вызова других методов (которые сами по себе являются результатами методов другого объекта).
Это предотвращает ситуацию, когда один объект вызывает метод другого объекта, который затем вызывает метод третьего объекта и так далее. В результате этого создается цепочка вызовов, в которой код становится сложным и трудным для понимания.Например, если у нас есть объект
A
, который вызывает метод у объектаB
, аB
, в свою очередь, вызывает метод у объектаC
, тоA
вряд ли должен непосредственно вызывать методы объектаC
. Вместо этого объектA
должен взаимодействовать только с объектами, непосредственно связанными с ним (в данном случае — с объектомB
).Объект должен взаимодействовать только с объектами, с которыми он непосредственно связан:
Если объект A работает с объектом B, то A может обращаться к методам B.
Однако A не должен обращаться к объектам, на которые указывает объект B (если объект B не является непосредственным партнером A). Таким образом, A не должен знать о внутренностях B.
Сокращение каскадных вызовов:
Законы Деметры также касаются каскадных вызовов, когда один объект вызывает другой объект через серию промежуточных объектов, например:Здесь, если
customer
взаимодействует с объектомaddress
, который в свою очередь взаимодействует с объектомstreet
, и тот — с объектомname
, то в идеале этого следовало бы избежать. Вместо этого, методgetStreetName()
должен быть добавлен вcustomer
, который возвращает нужное значение напрямую, а не через цепочку вызовов.
Пример нарушения закона Деметры
Представим, что у нас есть система для управления заказами:
Здесь объект Order
обращается к объекту Customer
, а тот — к объекту Address
, и в конце мы извлекаем значение из поля street
. Это пример каскадного вызова, и согласно закону Деметры, объект Order
не должен «знать» о внутренностях объектов Customer
и Address
. Вместо этого мы могли бы ввести метод в Order
для получения названия улицы:
Теперь код стал более читаемым и «закрытым» для изменений, потому что теперь Order
не зависит от структуры Customer
и Address
.
Почему закон Деметры важен?
Уменьшение связанности: Закон помогает уменьшить количество зависимостей между компонентами системы, что делает систему менее чувствительной к изменениям. Изменения в одном компоненте не приводят к каскадным изменениям в других компонентах.
Упрощение тестирования и сопровождения: Если объекты взаимодействуют друг с другом через интерфейсы, а не через подробные внутренности, это облегчает тестирование и поддержку кода, так как изменения в одном объекте с минимальной вероятностью повлияют на другие.
Улучшение читаемости кода: Когда объекты не «знают» о других объектах за пределами своей области ответственности, код становится более предсказуемым и понятным. Это также снижает вероятность ошибок, связанных с неправильным использованием внутренних деталей объекта.
Принцип инкапсуляции: Законы Деметры способствуют лучшему соблюдению принципов инкапсуляции, так как объекты должны скрывать свои внутренности и предоставлять доступ только через заранее определенные интерфейсы.
Реальные примеры и ограничения
Хотя закон Деметры полезен, есть ситуации, когда строгое следование этому принципу может быть затруднительным. Например, в некоторых случаях, например, в сложных моделях данных или при работе с API, требуется взаимодействие с несколькими уровнями объектов. Однако это не значит, что принцип не стоит соблюдать; скорее, он подсказывает, как уменьшить глубину вложенности и разбираться с объектами по необходимости.
Пример реального применения:
Скажем, у вас есть система, которая управляет заказами в интернет-магазине. Когда клиент размещает заказ, вам нужно обновить статус его заказа, а также обработать информацию о доставке и оплате. В рамках этого процесса, возможно, потребуется взаимодействовать с объектами, находящимися на разных уровнях абстракции, но все же важно следить за тем, чтобы один объект не становился зависимым от слишком большого числа объектов.
Заключение
Закон Деметры — это полезный принцип для разработки гибкого и легко сопровождаемого кода. Он помогает ограничить количество ненужных зависимостей между объектами и предотвращает нежелательные цепочки вызовов, которые могут затруднить тестирование и поддержку системы. Соблюдение этого принципа делает систему более устойчивой к изменениям, облегчает её понимание и повышает читаемость кода.