Введение

Программные системы состоят из модулей, которые мы можем условно поделить на низкоуровневые и высокоуровневые.

Низкоуровневые содержат утилитарную функциональность: обращение к БД, запросы к серверу, рендеринг DOM-элементов на странице.

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

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

Принцип инверсии зависимостей

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) предполагает, что:

  • Высокоуровневые модули не должны зависеть от низкоуровневых; оба типа должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.

Таким образом DIP помогает снизить сцепление модулей (coupling).

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

Сцепление и связность

Сцепление (coupling) не стоит путать со связностью (cohesion).

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

Связность — степень, в которой задачи некоторого модуля, связаны друг с другом. Чем выше связность, тем строже модули следуют SRP, тем выше сфокусирован модуль на конкретной задаче.

Абстракции

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

В примере c регулятором температуры на схеме ниже структура системы нарушает DIP. Модули зависят напрямую от других модулей, это увеличивает сцепление.

Модули зависят от конкретных модулей, это увеличивает сцепление

Исправленный вариант вводит прослойку между сущностями в виде абстракций — интерфейсов.

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

Абстракции в виде интерфейсов позволяют снизить сцепление

DIP и тестируемость

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

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

Коротко

Принцип инверсии зависимостей:

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

Материалы к разделу

Вопросы