Разница между инъекцией зависимостей (DI) и инверсией контроля (IOC)

117

Я видел много упоминаний о внедрении зависимостей (DI) и инверсии контроля (IOC), но я действительно не знаю, есть ли разница между ними или нет.

Я хотел бы начать использовать один или оба из них, но я немного смущен тем, как они отличаются.

комар
источник
Инверсия Контроля обычно относится к «контейнерам», в то время как Инъекция зависимостей относится к фактическому шаблону. Но они идут рука об руку. Я бы порекомендовал прочитать статью Мартина Фаулера, чтобы разобраться с этой темой.
Бен Хоффштейн
Внедрение зависимостей - это то, что вы делаете, что приводит к структуре команд, называемой Inversion of Control. Они по своей сути связаны.
2
DI является форма IoC, я дал довольно подробное объяснение DI и IoC в этом ответе
2
Я бы сказал, что DI - особый случай МОК. Традиционное управление отправляет модуль-> запрос модуля из менеджера модулей, в DI он инвертируется в менеджер модулей -> получает запрошенные зависимости от модуля.
Рафал Доугирд
Другими словами, в основном IoC - это реализация использования DI. Я правильно понял?
dance2die

Ответы:

53

Определения

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

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

Работая вместе

Инверсия управления может использовать внедрение зависимостей, потому что для создания компонентов, обеспечивающих определенные функциональные возможности, необходим механизм. Существуют и используются другие опции, например, активаторы, фабричные методы и т. Д., Но фреймворкам не нужно ссылаться на эти служебные классы, когда классы фреймворка могут вместо этого принять нужную (ые) зависимость (и).

Примеры

Одним из примеров этих концепций в работе является инфраструктура плагинов в Reflector . Плагины имеют большой контроль над системой, даже если приложение ничего не знало о плагинах во время компиляции. Для каждого из этих плагинов вызывается один метод: Initialize, если память служит, который передает управление плагину. Фреймворк не знает, что они будут делать, он просто позволяет им это делать. Контроль был взят из основного приложения и передан компоненту, выполняющему конкретную работу; инверсия контроля.

Инфраструктура приложения обеспечивает доступ к ее функциональности через различных поставщиков услуг. Плагин дает ссылки на поставщиков услуг при его создании. Эти зависимости позволяют плагину добавлять свои собственные пункты меню, изменять способ отображения файлов, отображать свою собственную информацию на соответствующих панелях и т. Д. Поскольку зависимости передаются через интерфейс, реализации могут измениться, и изменения не нарушат код до тех пор, пока договор остается в силе.

В то время фабричный метод использовался для создания плагинов с использованием информации о конфигурации, отражения и объекта Activator (по крайней мере, в .NET). Сегодня существуют инструменты, MEF для одного, которые позволяют использовать более широкий диапазон опций при внедрении зависимостей, включая возможность для среды приложения принимать список плагинов в качестве зависимости.

Резюме

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

цыпленок
источник
3
Нет, IoC - более старая концепция, и она не зависит от DI (который не зависит от IoC). Например, возьмем инфраструктуру Struts (Java): она сильно зависит от IoC, но не использует DI.
Rogério
1
@ Rogério - Вы делаете хорошее замечание, что эти два понятия не требуют друг друга. Я обновил свой ответ, чтобы прояснить это, а затем быстро опишу, как некоторые фреймворки используют их вместе, чтобы учесть код, который более слабо связан.
Chuck
Самым простым приложением IoC, вероятно, будет ActionListener. Вместо процедурной обработки кода, код обработки событий делегируется пользовательскому коду. Настоящим инвертируем управление.
микрофон
0

Хорошая статья для понимания МОК и DI http://martinfowler.com/articles/injection.html

МОК (инверсия контроля)

МОК означает

  1. кодирование интерфейса (один компонент должен зависеть от интерфейса другого компонента, а не от impl), и, например,

    interface iComp_2 {...}
    
    class Comp_1 {
        iComp_2 c2 = ….;
    }
    
  2. удаление конкретного кода реализации компонента, например

    Comp_1 {
        iComp_2 c2 = getComp_2_Impl(); // not new Comp_2_Impl();
    }
    

МОК может быть достигнуто одним из следующих:

1. DI (Внедрение зависимостей)

3 types of DI

1.1 Constructor Injection

1.2 Setter Injection

1.3 Interface Injection

2. Сервисный локатор

DI (Dependency Injection) контейнер

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

Создание impl после внедрения зависимостей: после определения impl он создает этот impl, сначала создавая все его зависимости (указанные в файле конфигурации), а затем вставляя эти зависимости в этот impl.

Управление жизненным циклом экземпляра: контейнеры DI обычно сохраняют ссылку только на объекты, для которых им необходимо управлять жизненными циклами или которые повторно используются для будущих инъекций, таких как синглтоны или мухи. Когда конфигурируется для создания новых экземпляров некоторых компонентов для каждого вызова контейнера, контейнер обычно просто забывает о созданном объекте. В противном случае сборщику мусора будет трудно собрать все эти объекты, когда они больше не используются.

Ятендра Гоэль
источник
6
Вы действительно читали статью об «инъекциях»? МОК не означает, что говорит этот ответ, совсем нет.
Rogério
-3

Я бы сказал, «Инверсия управления» - это способ разработки системы, в которой все модули рассматриваются как абстрактные объекты.

И «Внедрение зависимостей» - это реализация, в которой конкретное отношение между различными модулями определяется во время выполнения.

миллибар
источник
-4

Инверсия управления является общей концепцией, в функциональных языках обычно используется продолжение. Это позволит вам написать API, в котором обе стороны являются «вызывающими», а не «вызываемыми». В других, более статичных средах у вас нет такой возможности, поэтому вам нужен этот хак, чтобы вставить подсказки в поток управления.

Хавьер
источник