Инверсия контроля против внедрения зависимости
Согласно статье, написанной Мартином Фаулером, инверсия управления - это принцип, при котором поток управления программы инвертируется: вместо программиста, управляющего потоком программы, внешние источники (инфраструктура, службы, другие компоненты) принимают на себя управление Это. Как будто мы подключаем что-то к чему-то другому. Он привел пример с EJB 2.0:
Например, интерфейс Session Bean определяет ejbRemove, ejbPassivate (сохраняется во вторичном хранилище) и ejbActivate (восстанавливается из пассивного состояния). Вы не можете контролировать, когда эти методы вызываются, только то, что они делают. Контейнер звонит нам, мы не называем это.
Это приводит к разнице между фреймворком и библиотекой:
Инверсия управления - это ключевая часть того, что отличает фреймворк от библиотеки. Библиотека - это, по сути, набор функций, которые вы можете вызывать, в наши дни обычно организованные в классы. Каждый вызов выполняет некоторую работу и возвращает управление клиенту.
Я думаю, точка зрения, что DI - это IOC, означает, что зависимость объекта инвертирована: вместо этого он управляет своими собственными зависимостями, жизненным циклом... что-то другое делает это за вас. Но, как вы сказали мне о DI руками, DI не обязательно является МОК. У нас все еще может быть DI и нет МОК.
Тем не менее, в этой статье (из pococapsule, еще одной IOC Framework для C/C++) предлагается, что благодаря IOC и DI контейнеры IOC и структуры DI намного превосходят J2EE, поскольку J2EE смешивает код инфраструктуры с компонентами. таким образом, не делая его простым старым объектом Java/C++ (POJO/POCO).
Инверсия управляющих контейнеров, отличных от шаблона внедрения зависимостей (ссылка на архив)
Дополнительное чтение, чтобы понять, в чем проблема со старой платформой разработки на основе компонентов, что приводит ко второй статье, приведенной выше: почему и что такое Inversion of Control (ссылка на архив)
Мой вопрос: что такое МОК и ДИ? Я сбит с толку. Основанный на pococapsule, IOC является чем-то более значительным, чем просто инвертирование управления между объектами или программистами и средами.
25 ответов
IoC - это общий термин, означающий, что приложение не вызывает методы в платформе, а платформа вызывает реализации, предоставляемые приложением.
DI - это форма IoC, где реализации передаются в объект через поиск конструкторов / установщиков / служб, от которого объект будет "зависеть" для правильного поведения.
Например,IoC без использования DI будет шаблоном шаблона, потому что реализация может быть изменена только посредством подклассов.
DI Frameworks предназначены для использования DI и могут определять интерфейсы (или аннотации в Java), чтобы упростить передачу реализаций.
Контейнеры IoC - это структуры DI, которые могут работать за пределами языка программирования. В некоторых вы можете настроить, какие реализации использовать в файлах метаданных (например, XML), которые являются менее инвазивными. С некоторыми вы можете сделать IoC, что обычно невозможно, например, внедрить реализацию в pointcuts.
Смотрите также эту статью Мартина Фаулера.
Короче говоря, IoC - это гораздо более широкий термин, который включает, но не ограничивается, DI
Термин "инверсия управления" (IoC) изначально означал любой стиль программирования, в котором общая среда или среда выполнения контролировали ход программы.
До того, как у DI появилось имя, люди начали ссылаться на каркасы, которые управляют зависимостями, как инверсию контейнеров управления, и вскоре значение IoC постепенно сместилось к этому конкретному значению: инверсия контроля над зависимостями.
Инверсия управления (IoC) означает, что объекты не создают другие объекты, на которые они полагаются при выполнении своей работы. Вместо этого они получают нужные им объекты из внешнего источника (например, файла конфигурации xml).
Внедрение зависимостей (DI) означает, что это делается без вмешательства объекта, обычно с помощью компонента инфраструктуры, который передает параметры конструктора и задает свойства.
IoC (версия Control): - Это общий термин, реализованный несколькими способами (события, делегаты и т. Д.).
DI (Dpendency I njection): - DI является подтипом IoC и реализуется с помощью инжекции конструктора, инжектора сеттера или интерфейса.
Но Spring поддерживает только следующие два типа:
- Сеттер Инъекция
- DI, основанный на установщике, реализуется путем вызова методов сеттера на бинах пользователя после вызова конструктора без аргументов или статического метода фабрики без аргументов для создания экземпляра его бина.
- Конструктор Инъекция
- DI на основе конструктора реализуется путем вызова конструктора с несколькими аргументами, каждый из которых представляет коллаборатора. Используя это, мы можем проверить, что внедренные bean-компоненты не равны null и не работают быстро (время компиляции), поэтому при запуске самого приложения мы получаем
NullPointerException: bean does not exist
, Внедрение в конструктор - это лучшая практика для внедрения зависимостей.
- DI на основе конструктора реализуется путем вызова конструктора с несколькими аргументами, каждый из которых представляет коллаборатора. Используя это, мы можем проверить, что внедренные bean-компоненты не равны null и не работают быстро (время компиляции), поэтому при запуске самого приложения мы получаем
DI является подмножеством IoC
- IoC означает, что объекты не создают другие объекты, на которые они полагаются при выполнении своей работы. Вместо этого они получают нужные им объекты из внешнего сервиса (например, файла XML или отдельного сервиса приложения). Я использую 2 реализации IoC: DI и ServiceLocator.
- DI означает, что принцип IoC получения зависимого объекта выполняется без использования конкретных объектов, но абстракций (интерфейсов). Это делает все компоненты цепочки тестируемыми, потому что компонент более высокого уровня не зависит от компонента более низкого уровня, только от интерфейса. Максы реализуют эти интерфейсы.
IOC (Inversion Of Controller). Предоставление контроля контейнеру для получения экземпляра объекта называется Inversion of Control. Это означает, что вместо того, чтобы создавать объект с помощью оператора new, пусть контейнер сделает это за вас.
DI (Dependency Injection): способ внедрения свойств в объект называется Dependency Injection.
We have three types of Dependency injection
1) Constructor Injection
2) Setter/Getter Injection
3) Interface Injection
Spring будет поддерживать только Constructor Injection и Setter/Getter Injection.
Поскольку все ответы подчеркивают теорию, я хотел бы продемонстрировать на примере первого подхода:
Предположим, мы создаем приложение, которое содержит функцию отправки SMS-сообщений с подтверждением после отправки заказа. У нас будет два класса, один отвечает за отправку SMS (SMSService), а другой отвечает за сбор пользовательских данных (UIHandler), наш код будет выглядеть следующим образом:
public class SMSService
{
public void SendSMS(string mobileNumber, string body)
{
SendSMSUsingGateway(mobileNumber, body);
}
private void SendSMSUsingGateway(string mobileNumber, string body)
{
/*implementation for sending SMS using gateway*/
}
}
public class UIHandler
{
public void SendConfirmationMsg(string mobileNumber)
{
SMSService _SMSService = new SMSService();
_SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
}
}
Выше реализация не является ошибкой, но есть несколько вопросов:
-) Предположим, что в среде разработки вы хотите сохранить SMS, отправленные в текстовый файл, вместо использования шлюза SMS, чтобы достичь этого; в итоге мы изменим конкретную реализацию (SMSService) на другую реализацию, мы теряем гибкость и вынуждены переписывать код в этом случае.
-) Мы закончим смешивать обязанности классов, наш (UIHandler) никогда не должен знать о конкретной реализации (SMSService), это должно быть сделано вне классов с использованием "Интерфейсов". Когда это будет реализовано, это даст нам возможность изменить поведение системы путем замены (SMSService), используемого с другой фиктивной службой, которая реализует тот же интерфейс, эта служба будет сохранять SMS-сообщения в текстовом файле вместо отправки на mobileNumber.
Чтобы исправить вышеуказанные проблемы, мы используем интерфейсы, которые будут реализованы нашим (SMSService) и новым (MockSMSService), в основном новый интерфейс (ISMSService) будет демонстрировать такое же поведение обеих служб, как и код ниже:
public interface ISMSService
{
void SendSMS(string phoneNumber, string body);
}
Затем мы изменим нашу (SMSService) реализацию на реализацию интерфейса (ISMSService):
public class SMSService : ISMSService
{
public void SendSMS(string mobileNumber, string body)
{
SendSMSUsingGateway(mobileNumber, body);
}
private void SendSMSUsingGateway(string mobileNumber, string body)
{
/*implementation for sending SMS using gateway*/
Console.WriteLine("Sending SMS using gateway to mobile:
{0}. SMS body: {1}", mobileNumber, body);
}
}
Теперь мы сможем создать новый макетный сервис (MockSMSService) с совершенно другой реализацией, используя тот же интерфейс:
public class MockSMSService :ISMSService
{
public void SendSMS(string phoneNumber, string body)
{
SaveSMSToFile(phoneNumber,body);
}
private void SaveSMSToFile(string mobileNumber, string body)
{
/*implementation for saving SMS to a file*/
Console.WriteLine("Mocking SMS using file to mobile:
{0}. SMS body: {1}", mobileNumber, body);
}
}
На этом этапе мы можем изменить код в (UIHandler), чтобы легко использовать конкретную реализацию службы (MockSMSService), как показано ниже:
public class UIHandler
{
public void SendConfirmationMsg(string mobileNumber)
{
ISMSService _SMSService = new MockSMSService();
_SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
}
}
Мы достигли большой гибкости и реализовали разделение проблем в нашем коде, но все же нам нужно внести изменения в кодовую базу для переключения между двумя службами SMS. Поэтому нам нужно внедрить Dependency Injection.
Чтобы достичь этого, нам нужно реализовать изменение в нашем (UIHandler) конструкторе класса, чтобы передать через него зависимость, тем самым код, который использует (UIHandler), может определить, какую конкретную реализацию (ISMSService) использовать:
public class UIHandler
{
private readonly ISMSService _SMSService;
public UIHandler(ISMSService SMSService)
{
_SMSService = SMSService;
}
public void SendConfirmationMsg(string mobileNumber)
{
_SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
}
}
Теперь форма UI, которая будет общаться с классом (UIHandler), отвечает за передачу используемой реализации интерфейса (ISMSService). Это означает, что мы инвертировали элемент управления (UIHandler) больше не отвечает за решение, какую реализацию использовать, вызывающий код делает. Мы внедрили принцип инверсии управления, одним из которых является DI.
Код формы пользовательского интерфейса будет таким, как показано ниже:
class Program
{
static void Main(string[] args)
{
ISMSService _SMSService = new MockSMSService(); // dependency
UIHandler _UIHandler = new UIHandler(_SMSService);
_UIHandler.SendConfirmationMsg("96279544480");
Console.ReadLine();
}
}
Вместо того, чтобы напрямую противопоставлять DI и IoC, может быть полезно начать с самого начала: каждое нетривиальное приложение зависит от других частей кода.
Итак, я пишу класс, и мне нужно вызвать метод ... каким-то образом мне нужно получить экземпляр. Самый простой и понятный способ - создать его сам.
YourService service = new YourServiceImpl();
Прямое создание экземпляра - это традиционный (процедурный) способ получения зависимости. Но у него есть ряд недостатков, включая тесную привязку к, что затрудняет изменение и тестирование моего кода. не заботится о том, как выглядит реализация, поэтому не хочет нести ответственность за ее создание.
Я бы предпочел переложить эту ответственность на что-то внешнее. Самый простой способ сделать это - просто переместить вызов создания экземпляра (
Проблема в том, что он по-прежнему отвечает за вызов локатора / фабрики / любого другого. Поскольку все, что я сделал, чтобы инвертировать зависимость, - это вставить посредника, теперь я связан с посредником (даже если я не связан с конкретными объектами, которые дает мне посредник).
Мне все равно, откуда берутся мои зависимости, поэтому я бы предпочел не отвечать за вызовы для их получения. Инвертирования самой зависимости было недостаточно. Я хочу инвертировать контроль над всем процессом.
Мне нужен совершенно отдельный фрагмент кода, который подключается (назовите его фреймворком). Тогда единственная ответственность, которая у меня остается, - заявить о своей зависимости от
Есть разные способы подключения к фреймворку. Инъекция - один из таких механизмов, с помощью которого я просто объявляю поле или параметр, которые, как я ожидаю, должен предоставить фреймворк, обычно, когда он создает экземпляр
Я думаю, что иерархия отношений между всеми этими концепциями немного сложнее, чем то, что показывают другие диаграммы в этом потоке; но основная идея состоит в том, что это иерархические отношения. Я думаю, что это синхронизируется с DIP в дикой природе.
IoC - Инверсия управления - это общий термин, независимый от языка, на самом деле он не создает объекты, а описывает, в каком режиме создается объект моды.
DI - Dependency Injection - это конкретный термин, в котором мы предоставляем зависимости объекта во время выполнения, используя различные методы внедрения, а именно. Инъекция сеттера, инжектор конструктора или интерфейсная инъекция.
Но весенняя документация говорит, что они одинаковы.
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
В первой строке "IoC также известен как внедрение зависимостей (DI)".
Инверсия контроля - это парадигма дизайна, целью которой является предоставление большего контроля целевым компонентам вашего приложения, которые выполняют работу.
Внедрение зависимостей - это шаблон, используемый для создания экземпляров объектов, на которые полагаются другие объекты, не зная во время компиляции, какой класс будет использоваться для предоставления этих функций.
Существует несколько основных методов реализации инверсии управления. Это:
- Используя фабричный образец
- Использование шаблона поиска сервисов
- Используя внедрение зависимости любого данного ниже типа:
1). Конструктор инъекций
2). Сеттер для инъекций
3). Внедрение интерфейса
DI и IOC - это два шаблона проектирования, которые в основном направлены на обеспечение слабой связи между компонентами или просто на способ, которым мы отделяем обычные отношения зависимости между объектами, чтобы объекты не были тесно связаны друг с другом.
Следующими примерами я пытаюсь объяснить обе эти концепции.
Ранее мы пишем такой код
Public MyClass{
DependentClass dependentObject
/*
At somewhere in our code we need to instantiate
the object with new operator inorder to use it or perform some method.
*/
dependentObject= new DependentClass();
dependentObject.someMethod();
}
С внедрением Dependency, инжектор зависимостей позаботится о создании объектов
Public MyClass{
/* Dependency injector will instantiate object*/
DependentClass dependentObject
/*
At somewhere in our code we perform some method.
The process of instantiation will be handled by the dependency injector
*/
dependentObject.someMethod();
}
Вышеупомянутый процесс передачи управления некоторому другому (например, контейнеру) для создания экземпляра и внедрения может быть назван инверсией управления, а процесс, в котором контейнер IOC вводит зависимость для нас, может быть назван внедрением зависимости.
IOC - это принцип, в котором управляющий поток программы инвертируется: вместо программиста, управляющего потоком программы, программа управляет потоком, уменьшая накладные расходы для программиста. Процесс, используемый программой для внедрения зависимости, называется DI
Эти две концепции работают вместе, предоставляя нам возможность писать гораздо более гибкий, многократно используемый и инкапсулированный код, что делает их важными концепциями при разработке объектно-ориентированных решений.
Также рекомендую к прочтению.
Что такое внедрение зависимостей?
Вы также можете проверить один из моих похожих ответов здесь
Inversion of Control - это общий принцип проектирования архитектуры программного обеспечения, который помогает создавать модульные программные структуры многократного использования, которые просты в обслуживании.
Это принцип разработки, при котором поток управления "принимается" из общей библиотеки или кода многократного использования.
Чтобы понять это лучше, давайте посмотрим, как мы использовали кодирование в наши ранние дни кодирования. В процедурных / традиционных языках бизнес-логика, как правило, контролирует поток приложения и "вызывает" общий или повторно используемый код / функции. Например, в простом консольном приложении мой поток управления контролируется инструкциями моей программы, которые могут включать в себя вызовы некоторых общих повторно используемых функций.
print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);
//More print and scan statements
<Do Something Interesting>
//Call a Library function to find the age (common code)
print Age
В отличие от этого, с IoC, фреймворки представляют собой повторно используемый код, который "вызывает" бизнес-логику.
Например, в системе на основе Windows уже будет доступна инфраструктура для создания элементов пользовательского интерфейса, таких как кнопки, меню, окна и диалоговые окна. Когда я пишу бизнес-логику своего приложения, это будут события фреймворка, которые будут вызывать мой код бизнес-логики (когда событие запускается), а НЕ наоборот.
Хотя код фреймворка не знает о моей бизнес-логике, он все равно будет знать, как вызывать мой код. Это достигается с помощью событий / делегатов, обратных вызовов и т. Д. Здесь управление потоком является "инвертированным".
Таким образом, вместо зависимости потока управления от статически связанных объектов, поток зависит от общего графа объектов и отношений между различными объектами.
Внедрение зависимостей - это шаблон проектирования, который реализует принцип IoC для разрешения зависимостей объектов.
Проще говоря, когда вы пытаетесь написать код, вы будете создавать и использовать разные классы. Один класс (класс A) может использовать другие классы (класс B и / или D). Итак, класс B и D являются зависимостями класса A.
Простая аналогия будет классом автомобилей. Автомобиль может зависеть от других классов, таких как двигатель, шины и многое другое.
Внедрение зависимостей предполагает, что вместо зависимых классов (здесь Class Car), создающих свои зависимости (Class Engine и класс Tire), класс должен быть внедрен с конкретным экземпляром зависимости.
Давайте разберемся с более практичным примером. Учтите, что вы пишете свой собственный TextEditor. Среди прочего, вы можете иметь проверку орфографии, которая предоставляет пользователю возможность проверить опечатки в его тексте. Простая реализация такого кода может быть:
Class TextEditor
{
//Lot of rocket science to create the Editor goes here
EnglishSpellChecker objSpellCheck;
String text;
public void TextEditor()
{
objSpellCheck = new EnglishSpellChecker();
}
public ArrayList <typos> CheckSpellings()
{
//return Typos;
}
}
На первый взгляд все выглядит радужно. Пользователь напишет какой-нибудь текст. Разработчик захватит текст и вызовет функцию CheckSpellings и найдет список опечаток, которые он покажет пользователю.
Кажется, все работает отлично, пока в один прекрасный день один пользователь не начнет писать по-французски в редакторе.
Чтобы обеспечить поддержку большего количества языков, нам нужно иметь больше SpellCheckers. Вероятно, французский, немецкий, испанский и т. Д.
Здесь мы создали тесно связанный код с "английским"SpellChecker, тесно связанным с нашим классом TextEditor, что означает, что наш класс TextEditor зависит от EnglishSpellChecker или, другими словами, EnglishSpellCheker является зависимостью для TextEditor. Нам нужно удалить эту зависимость. Кроме того, нашему текстовому редактору нужен способ хранить конкретную ссылку любого средства проверки орфографии на основе усмотрения разработчика во время выполнения.
Итак, как мы видели во введении DI, он предполагает, что класс должен быть введен со своими зависимостями. Таким образом, вызывающий код должен отвечать за внедрение всех зависимостей в вызываемый класс / код. Таким образом, мы можем реструктурировать наш код как
interface ISpellChecker
{
Arraylist<typos> CheckSpelling(string Text);
}
Class EnglishSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
Class FrenchSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
В нашем примере класс TextEditor должен получить конкретный экземпляр типа ISpellChecker.
Теперь зависимость может быть введена в Constructor, Public Property или метод.
Давайте попробуем изменить наш класс, используя Constructor DI. Измененный класс TextEditor будет выглядеть примерно так:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
Чтобы вызывающий код при создании текстового редактора мог внедрить соответствующий тип SpellChecker в экземпляр TextEditor.
Вы можете прочитать полную статью здесь
МОК - DIP - DI
- Инверсия управления (IOC)
- Принцип инверсии зависимостей (DIP)
- Внедрение зависимостей (DI)
1- IOC: абстрактный принцип, описывающий аспект некоторых проектов архитектуры программного обеспечения, в котором поток управления системой инвертируется по сравнению с процедурным программированием.
2-DIP: это принцип объектно-ориентированного программирования (ООП) (D от SOLID).
3-DI: это шаблон проектирования программного обеспечения, который реализует инверсию управления и позволяет дизайну программы следовать принципу инверсии зависимостей.
IOC и DIP - это два непересекающихся набора, а DIP - это супер набор DI, локатора услуг и некоторых других шаблонов.
IOC(Inversion Of Controller): Предоставление контроля контейнеру для получения экземпляра объекта называется Inversion of Control. Это означает, что вместо того, чтобы создавать объект с помощью оператора new, пусть контейнер сделает это за вас.
DI (Dependency Injection). Передача необходимых параметров (свойств) из XML в объект (в POJO CLASS) называется внедрением Dependency Injection.
IOC (Inversion of Control) - это, по сути, концепция шаблона проектирования, заключающаяся в удалении зависимостей и их разделении, чтобы сделать поток нелинейным и позволить контейнеру / или другому объекту управлять предоставлением зависимостей. Это на самом деле следует голливудскому принципу "Не звоните нам, мы вам позвоним". Итак, подытоживая различия.
Инверсия управления:- это общий термин для разделения зависимостей и делегирования их предоставления, и это может быть реализовано несколькими способами (события, делегаты и т. Д.).
Внедрение зависимостей:- DI является подтипом IOC и реализуется путем инжекции в конструктор, вложения метода или метода.
Следующая статья описывает это очень аккуратно.
https://www.codeproject.com/Articles/592372/Dependency-Injection-DI-vs-Inversion-of-Control-IO
IOC указывает, что внешние классы управляют классами приложения, а внешние классы означают, что контейнер управляет зависимостью между классом приложения. Основная концепция IOC заключается в том, что программисту не нужно создавать ваши объекты, а описывать, как они должны создаваться.
Основные задачи, выполняемые контейнером IoC: создание экземпляра класса приложения. настроить объект. собрать зависимости между объектами.
DI - это процесс предоставления зависимостей объекта во время выполнения с использованием внедрения сеттера или конструктора.
Я думаю, что идея может быть продемонстрирована ясно, не вдаваясь в объектно-ориентированные сорняки, которые, кажется, запутывают идею.
// dependency injection
function doSomething(dependency) {
// do something with your dependency
}
// in contrast to creating your dependencies yourself
function doSomething() {
dependency = getDependencySomehow()
}
// inversion of control
application = makeApp(authenticate, handleRequest, sendResponse)
application.run(getRequest())
// in contrast to direct control or a "library" style
application = makeApp()
request = application.getRequest()
if (application.authenticate(request.creds)) {
response = application.handleRequest(request)
application.sendResponse(response)
}
Если вы наклоните голову и прищурите глаза, вы увидите, что DI - это конкретная реализация IoC с определенными проблемами. Вместо того, чтобы внедрять модели и поведения в структуру приложения или операции более высокого порядка, вы вводите переменные в функцию или объект.
Концепция IoC была впервые услышана в эпоху процедурного программирования. Поэтому из исторического контекста IoC говорил об инверсии владенияпотоком управления, то есть кто несет ответственность за вызов функций в желаемом порядке - будь то сами функции или если вы должны инвертировать его в какую-то внешнюю сущность.
Однако как только появилось ООП, люди начали говорить о IoC в контексте ООП, где приложения связаны с созданием объектов и их отношениями, помимо потока управления. Такие приложения хотели инвертировать право владения созданием объекта (а не потоком управления) и требовали контейнера, который отвечает за создание объекта, жизненный цикл объекта и внедрение зависимостей объектов приложения, тем самым исключая объекты приложения из создания другого конкретного объекта.
В этом смысле DI - это не то же самое, что IoC, поскольку это не поток управления, но это своего рода Io *, т.е. инверсия владения созданием объекта.
Давайте начнем с D SOLID и посмотрим на DI и IoC из книги Скотта Миллета "Профессиональные шаблоны проектирования ASP.NET":
Принцип обращения зависимостей (DIP)
DIP предназначен для изоляции ваших классов от конкретных реализаций, а их зависимость от абстрактных классов или интерфейсов. Он продвигает мантру кодирования к интерфейсу, а не к реализации, что повышает гибкость в системе, гарантируя, что вы не будете тесно связаны с одной реализацией.
Инъекция зависимости (DI) и инверсия контроля (IoC)
С DIP тесно связаны принцип DI и принцип IoC. DI - это акт предоставления низкоуровневого или зависимого класса через конструктор, метод или свойство. Используемые вместе с DI, эти зависимые классы могут быть преобразованы в интерфейсы или абстрактные классы, что приведет к слабосвязанным системам, которые легко тестируются и легко изменяются.
В IoC поток управления системой инвертирован по сравнению с процедурным программированием. Примером этого является контейнер IoC, целью которого является внедрение сервисов в клиентский код без указания клиентским кодом конкретной реализации. В этом случае управление, которое инвертируется, является действием клиента, получающего услугу.
Millett, C (2010). Профессиональные шаблоны проектирования ASP.NET. Wiley Publishing. 7-8.
DIP против DI против IoC
[Принцип инверсии зависимостей (DIP)] является частью
SOLID
[About], которые просят вас использовать абстракцию вместо реализаций
Injection Dependency(DI) - используйте Aggregation вместо Composition [About] В этом случае внешний объект отвечает за логику внутри. Что позволяет использовать более динамичный и проверяемый подход.
class A {
B b
//injecting B via constructor
init(b: B) {
self.b = b
}
}
Инверсия управления (IoC) очень высокого уровня определения, который больше касается потока управления. Лучший пример -
Inversion of Control(IoC) Container or Framework
. Например, графический интерфейс, который представляет собой Framework, где у вас нет элемента управления, все, что вы можете сделать, это просто реализовать интерфейс Framework, который будет вызываться, когда в Framework произойдет какое-либо действие. Таким образом, управление передается из вашего приложения в используемую платформу.
DIP + DI
class A {
IB ib
init(ib: IB) {
self.ib = ib
}
}
Также вы можете добиться этого, используя:
Более сложный пример
Правило зависимости в многоуровневой / модульной структуре
Псевдокод:
interface InterfaceInputPort {
func input()
}
interface InterfaceOutputPort {
func output()
}
class A: InterfaceOutputPort {
let inputPort = B(outputPort: self)
func output() {
print("output")
}
}
class B: InterfaceInputPort {
let outputPort: InterfaceOutputPort
init(outputPort: InterfaceOutputPort) {
self.outputPort = outputPort
}
func input() {
print("input")
}
}
Что касается этого вопроса, я бы сказал, что вики уже предоставила подробные и понятные объяснения. Я просто процитирую наиболее значимые здесь.
В объектно-ориентированном программировании есть несколько основных методов для реализации инверсии управления. Это:
- Использование шаблона сервисного локатора Использование внедрения зависимостей, например, инъекция в конструктор.
- Использование контекстного поиска;
- Использование шаблонного метода проектирования шаблона;
- Использование шаблона проектирования стратегии
Что касается внедрения зависимости
Внедрение зависимостей - это метод, при котором один объект (или статический метод) предоставляет зависимости другого объекта. Зависимость - это объект, который можно использовать (сервис). Инъекция - это передача зависимости зависимому объекту (клиенту), который будет ее использовать.
IoC, также известный как инверсия управления, относится к управлению созданием экземпляров, осуществляемому контейнером Spring. Управление созданием и конструированием объектов осуществляется контейнером. Контейнер создает объекты и внедряет их в наше приложение.
1) DI - это Child->obj, зависит от parent-obj. Глагол зависит важно. 2) МОК - это Child->obj, выступающий под платформой. где платформой может быть школа, колледж, танцевальный класс. Здесь выполняются действия с различными последствиями под любым поставщиком платформы.
практический пример: `
//DI
child.getSchool();
//IOC
child.perform()// is a stub implemented by dance-school
child.flourish()// is a stub implemented by dance-school/school/
`
-AB
Я нашел лучший пример на Dzone.com, который действительно полезен для понимания реальных различий между IOC и DI.
"IoC - это когда кто-то другой создает объекты для вас". Поэтому вместо того, чтобы писать "новое" ключевое слово (например, MyCode c=new MyCode()) в вашем коде, объект создается кем-то другим. Этот "кто-то еще" обычно называется контейнером IoC. Это означает, что мы передаем rrsponsibility (control) контейнеру, чтобы получить экземпляр объекта, называемый Inversion of Control., Означает, что вместо того, чтобы создавать объект с помощью оператора new, пусть контейнер сделает это за вас.
DI(Dependency Injection): Way of injecting properties to an object is
called
Dependency injection.
We have three types of Dependency injection
1) Constructor Injection
2) Setter/Getter Injection
3) Interface Injection
Spring will support only Constructor Injection and Setter/Getter Injection.
//ICO, DI,10 лет назад, вот так:
public class AuditDAOImpl implements Audit{
//dependency
AuditDAO auditDAO = null;
//Control of the AuditDAO is with AuditDAOImpl because its creating the object
public AuditDAOImpl () {
this.auditDAO = new AuditDAO ();
}
}
Теперь с весной 3,4 или последним, как показано ниже
public class AuditDAOImpl implements Audit{
//dependency
//Now control is shifted to Spring. Container find the object and provide it.
@Autowired
AuditDAO auditDAO = null;
}
В целом, управление инвертировано из старой концепции связанного кода в фреймворки, такие как Spring, что делает объект доступным. Так что, насколько я знаю, это IOC и внедрение зависимостей, как вы знаете, когда мы внедряем зависимый объект в другой объект, используя конструктор или сеттеры. Inject в основном означает передачу его в качестве аргумента. Весной у нас есть конфигурация на основе XML и аннотаций, в которой мы определяем объект bean и передаем зависимый объект в стиле конструктора или инжектора сеттера.