Как именно внедрение зависимостей уменьшает связь? - PullRequest
10 голосов
/ 28 декабря 2010

Я много читал о внедрении зависимостей, но понятия не имею, как это на самом деле уменьшает связь?

Аналогия с DI, которую я имею, состоит в том, что все компоненты зарегистрированы в контейнере,они как в сундуке с сокровищами.Чтобы получить компонент, вы, очевидно, сначала регистрируете его, но затем вам придется опросить сундук с сокровищами (который похож на слой косвенности).Это правильная аналогия?Однако не ясно, как происходит «инъекция» (как бы это соответствовало этой аналогии?).

Спасибо

Ответы [ 4 ]

39 голосов
/ 28 декабря 2010

Dependency Injection (DI) не уменьшает связывание как таковое, потому что компонент, который полагается на зависимость, все еще связан с ее зависимостью. Однако, что DI делает , так это снять ответственность за поиск зависимости от самого компонента и передать эту ответственность в другом месте.

Компонент, который полагается на DI, является полностью пассивным, когда дело доходит до его зависимостей. В компоненте нет кода, который говорит «создайте новый экземпляр этой зависимости» или «выйдите и принесите мне эту зависимость». Зависимость предоставляется компоненту (внедренному в него), обычно, когда сам компонент создается каким-либо другим объектом.

Это изменение ответственности за создание (или запрос на создание) зависимости называется Inversion of Control (IoC).

Итак, если компонент не знает, как создать или запросить зависимость, где лежит эта ответственность? Обычно в объекте, созданном специально для разрешения зависимостей, обычно называемом контейнером IoC. По вашей аналогии, это ваш «сундук с сокровищами». Контейнер IoC содержит инструкции, которые в основном говорят: «когда кто-то запрашивает этот , дайте ему один из них . Контейнер IoC обычно может проверять компонент, который его просят создать, выяснить, что его зависимости, и их тоже, идут по «цепочке зависимостей», пока все зависимости не будут разрешены.

Большой сдвиг в мышлении, инъекция, происходит при принятии решения * кто будет спрашивать контейнер о зависимости компонента "? Без DI сам компонент будет запрашивать контейнер для его зависимости. Однако, используя DI ответственность за запрос контейнера «разрешить» зависимость компонента падает на то, что создает или использует компонента. Когда компонент создается, все, что его создает, несет ответственность за обеспечение все зависимости. Компонент не знает и не заботится о том, как они создаются, просто они есть.

Теперь, если зависимость определена как конкретная реализация, компонент все еще тесно связан с этой конкретной конкретной реализацией, даже если она внедряется. Сам DI не уменьшает сцепление в этом смысле. Но если зависимость определяется как интерфейс , компонент не заботится и не знает, что такое конкретная реализация или как она создается. Это все еще связано с зависимостью, но это очень слабая связь .

В этом смысле «Внедрение зависимостей» и «Программирование на интерфейсах» объединяются для создания очень слабо связанных, очень гибких компонентов.

4 голосов
/ 28 декабря 2010

В качестве аналогии с вашими компонентами, находящимися в сундуке с сокровищами: Система (скажем, полировщик сокровищ) без инъекции зависимостей должна иметь возможность выбирать предмет из самого сундука с сокровищами. Он должен иметь некоторое представление о природе зависимости, чтобы выбрать правильное сокровище для полировки в зависимости от текущего контекста. Таким образом сцепление.

В сценарии DI вашему полировщику сокровищ вообще не нужно знать о существовании сундука с сокровищами. Все, что нужно знать, это то, что в какой-то момент (предпочтительно при создании) полировщику будет предоставлен (введен) объект, который реализует ITreasure:

interface ITreasure
{
    void PolishMe();
}

Таким образом, ваш класс реализации отделен от вашего сундука с сокровищами.

3 голосов
/ 28 декабря 2010

Связь особенно снижается при правильном использовании интерфейсов.

Если клиент знает только об интерфейсе, теперь открываются возможности. Вы можете ввести свою собственную реализацию или прокси-версию; вы можете посоветовать это с аспектами без ведома клиента; Вы можете легко издеваться над ним во время тестирования. Клиенту не нужно знать конкретный тип, как если бы вы просто назвали «new».

1 голос
/ 28 декабря 2010

В DI один компонент вызывает другой компонент только через четко определенный интерфейс, и все компоненты «склеиваются» вместе через конфигурацию, а не код.
В результате мы можем поменять реализации, используемые приложением, только путем переконфигурации.
В качестве примера в контейнерах вы можете визуализировать внедрение зависимостей как обратный поиск (если вы использовали JNDI). Вместо того, чтобы жестко кодировать имена ресурсов / модулей, вы объявляете, что нужно для класса (действующего как bean-компонент). Контейнер отвечает за предоставление всего во время выполнения.
Этот термин был придуман Мартином Фаулером, и вы можете проверить его статью о понятии DI

...