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.
Простая аналогия будет классом Car.Автомобиль может зависеть от других классов, таких как Engine, Tyres и т. Д.
Внедрение зависимостей предполагает, что вместо зависимых классов (класс автомобилей здесь), создающих свои зависимости (класс 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 DI.Измененный класс TextEditor будет выглядеть примерно так:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
Так что вызывающий код при создании текстового редактора может внедрить соответствующий тип SpellChecker в экземпляр TextEditor.
Вы можетечитать статью полностью здесь