Как инъекция зависимости увеличивает связь?

32

На странице Википедии, посвященной внедрению зависимостей, раздел о недостатках говорит нам об этом:

Внедрение зависимостей увеличивает связь, требуя от пользователя подсистемы обеспечивать потребности этой подсистемы.

со ссылкой на статью против внедрения зависимостей .

Внедрение зависимостей заставляет класс использовать интерфейс вместо конкретной реализации. Это должно привести к снижению сцепления , нет?

Чего мне не хватает? Как внедрение зависимостей увеличивает связь между классами?

BЈовић
источник
2
Я не уверен, кто написал этот список недостатков, но я взял бы это с зерном соли. Например, я видел, как DI уменьшал размер кодовой базы на 2/3, устраняя тонну избыточного кода настройки.
Роб
@RobY Я в основном использовал фабрику для внедрения зависимости, и мой опыт показывает, что это увеличивает размер кода, но упрощает тестирование.
BЈовић
Попробуйте использовать альтернативу, такую ​​как Registry или Context Passing;) Или код, который просто создает экземпляры объектов, а затем извлекает их свойства из конфигурации. В основном я говорю о разнице между сейчас и 15 лет назад.
Роб
Связанный: stackoverflow.com/a/9503612/264697 . Ответ Марка Симанна объясняет, как общая связь снижается с помощью Dependency Injection.
Стивен

Ответы:

42

Итак, что мне не хватает?

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

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

Telastyn
источник
Да, сцепление уменьшается в одну сторону и увеличивается в другом.
Пол Дрейпер
Но потребитель не создает его; это скорее точка.
Кейси
@emodendroket - А? Инверсия контроля позволяет потребителю не создавать его. Инъекция зависимости ортогональна этому.
Теластин
Ну, вы делаете различие, с которым я не знаком, так как обычно эти термины взаимозаменяемы.
Кейси
22

Предположим, у вас есть подсистема, Sкоторая зависит от соединения с базой данных D. Без внедрения зависимости существует относительно тесная связь между Sи D, потому что Sнужно знать, как использовать Dи как ее создавать. Однако остальная часть системы может блаженно не знать об этой зависимости между Sи D.

С внедрением зависимостей связь между Sи Dстановится более свободной, потому что вы удаляете из Sзнания, как создать D. Sпросто нужно знать, как его использовать. Повышенная общая связь обусловлена ​​тем фактом, что другие части системы теперь должны знать Dи, возможно, как ее создать. Степень этого увеличения связи зависит от того, как зависимость Dвводится в S:

  • При внедрении конструктора создатель Sнуждается в зависимости Dи, возможно, в знаниях, как его создать.
  • При внедрении на уровне метода каждый вызывающий метод, Sчерез который Dвводится метод, нуждается в зависимости Dи, возможно, в знаниях о том, как его создать.

В любом случае, количество классов, которое зависит от Dувеличения, и знания о том, как создать Dвсе еще должны присутствовать где-то в системе. Это создает общее увеличение сцепления.

Барт ван Инген Шенау
источник
Хорошо, это имеет смысл для конструктора и сеттера. Но если использовать фабричный или стратегический паттерн, создание перемещается туда, а класс использует только внедренный объект. Или это не внедрение зависимости (только инверсия контроля)?
BЈовић
Даже с фабричной инъекцией, создатель Sдолжен предоставить фабрику D, что означает, что он должен знать, что Sиспользует D(или, по крайней мере, какой-то его интерфейс).
Идан Арье
7

Я категорически не согласен, что это увеличивает сцепление.

Без внедрения зависимости у вас есть тесная связь между подсистемой и конкретной реализацией зависимости.

С внедрением зависимости вы отсоединили подсистему от реализации зависимости.

Утверждение о том, что это увеличивает связь между потребителем и этой подсистемой, ОЧЕНЬ сомнительно, поскольку подразумевает, что потребитель теперь тесно связан с зависимостью, требуемой подсистемой. Все это означает, что вы пишете тесно связанный код, который связывает вашего потребителя с зависимостью. В идеале ВСЕ ваш код отделен.

Конструктор Инъекция:

Разрешение зависимостей обрабатывается контейнером внедрения зависимостей или фабрикой. Потребитель может получить конкретную реализацию подсистемы из контейнера ввода зависимостей или с фабрики.

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

Метод инъекции:

То же, что и инъекция в конструктор, за исключением того, что теперь потребителю нужно получить конкретный экземпляр зависимости из контейнера или фабрики (или даже вставить его метод / конструктор) и внедрить его в метод. Опять же, потребитель не связан с конкретной реализацией зависимости.

TL; DR Наихудший случай для внедрения зависимостей в подсистеме - это то, что связь сдвинута на потребительский код. НЕТ ОБЩЕГО УВЕЛИЧЕНИЯ МУФТЫ.

В лучшем случае все системы теперь слабо связаны, а внедрение зависимостей контролируется через контейнеры или фабрики внедрения зависимостей.

ястреб
источник