Інверсія управління - це загальний принцип дизайну архітектури програмного забезпечення, який допомагає створювати багаторазові, модульні програмні рамки, які прості в обслуговуванні.
Це принцип дизайну, в якому Потік управління "отримується" з загальнонаписаної бібліотеки або коду для багаторазового використання.
Щоб краще зрозуміти це, давайте подивимось, як ми звикли кодувати в попередні дні кодування. У процедурній / традиційній мовах бізнес-логіка, як правило, контролює потік програми та "викликає" загальний або багаторазовий код / функції. Наприклад, у простому додатку консолі мій потік управління контролюється вказівками моєї програми, які можуть включати виклики до деяких загальних функцій багаторазового використання.
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, Frameworks - це багаторазовий код, який "викликає" ділову логіку.
Наприклад, у системі на базі Windows вже буде доступна рамка для створення елементів інтерфейсу, таких як кнопки, меню, вікна та діалогові вікна. Коли я пишу бізнес-логіку моєї заявки, події фреймворку називатимуть моїм кодом ділової логіки (коли подія запускається), а НЕ навпаки.
Хоча код рамки не знає моєї ділової логіки, він все одно буде знати, як викликати мій код. Це досягається за допомогою подій / делегатів, зворотних дзвінків тощо. Тут управління потоком "перевернуте".
Отже, замість залежності потоку управління на статично пов'язаних об'єктах потік залежить від загального графіка об'єкта та відносин між різними об'єктами.
Dependency Injection - це схема проектування, яка реалізує принцип IoC для вирішення залежностей об'єктів.
Простіше кажучи, коли ви намагаєтеся написати код, ви будете створювати та використовувати різні класи. Один клас (клас A) може використовувати інші класи (клас B та / або D). Отже, клас B і D - залежності класу А.
Простий аналогією буде автомобіль класу. Автомобіль може залежати від інших класів, таких як Двигун, Шини тощо.
Інжекція залежності залежить від того, щоб замість залежних класів (Class Class тут) створювати свої залежності (Class Engine і Class 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 Properties або метод.
Давайте спробуємо змінити наш клас за допомогою Constructor DI. Змінений клас TextEditor буде виглядати приблизно так:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
Так що викликовий код під час створення текстового редактора може вводити відповідний SpellChecker Type в екземпляр TextEditor.
Повну статтю ви можете прочитати тут