Що таке інверсія управління?


1825

Інверсія управління (IoC) може бути дуже заплутаною, коли вона вперше зустрічається.

  1. Що це?
  2. Яку проблему вона вирішує?
  3. Коли це доцільно використовувати, а коли ні?

292
Проблема більшості цих відповідей - це використовувана термінологія. Що таке контейнер? Інверсія? Залежність? Поясніть це простим словом без великих слів.
kirk.burleson


8
Це впорскування в залежність (DI) - дивіться інформацію про Мартіна Фаулерса
Рікардо Санчес


Це прикметник, а не іменник, це не річ, це опис зміни, внесеної до коду, де контроль потоку знаходиться в делегаті, а не контейнер.
Мартін Спамер

Відповіді:


1523

Шаблони інверсії керування (IoC) та введення залежностей (DI) - це все про усунення залежностей із вашого коду.

Наприклад, скажімо, що у вашій програмі є компонент текстового редактора, і ви хочете перевірити орфографію. Ваш стандартний код виглядатиме приблизно так:

public class TextEditor {

    private SpellChecker checker;

    public TextEditor() {
        this.checker = new SpellChecker();
    }
}

Те, що ми тут зробили, створює залежність між TextEditorта SpellChecker. У сценарії IoC ми б замість цього зробили щось подібне:

public class TextEditor {

    private IocSpellChecker checker;

    public TextEditor(IocSpellChecker checker) {
        this.checker = checker;
    }
}

У першому прикладі коду ми instantiating SpellChecker( this.checker = new SpellChecker();), що означає, що TextEditorклас безпосередньо залежить від SpellCheckerкласу.

У другому прикладі коду ми створюємо абстракцію, маючи SpellCheckerклас залежності в TextEditorпідписі конструктора 's (не ініціалізуючи залежність у класі). Це дозволяє нам викликати залежність, а потім передавати її в клас TextEditor так:

SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);

Тепер клієнт, що створює TextEditorклас, має контроль над тим, яку SpellCheckerреалізацію використовувати, оскільки ми вводимо залежність у TextEditorпідпис.


50
Хороший чіткий приклад. Однак, припустимо, замість того, щоб вимагати передачі інтерфейсу ISpellChecker конструктору об'єкта, ми відкрили його як властивість настройки (або метод SetSpellChecker). Чи все-таки це буде IoC?
devios1

25
chainguy1337 - так, було б. Використання подібних сеттерів називається інжекцією сеттера на відміну від введення конструктора (обидві методи введення залежності). IoC є досить загальною схемою, але ін'єкція залежностей активізує IoC
Jack Ukleja

257
Незважаючи на безліч голосів, ця відповідь є неправильною. Перегляньте martinfowler.com/articles/injection.html#InversionOfControl . Зокрема, зверніть увагу на частину, що говорить: "Інверсія контролю є надто загальним терміном, і, таким чином, люди вважають його заплутаним. В результаті багато дискусій з різними захисниками IoC ми зупинилися на назві Dependency Injection".
Rogério

45
Я згоден з @Rogeria. це не пояснює, чому його називають IoC, і я здивований кількістю голосів, що піднялися ;-)
Аравінд Яррам

31
Я боком з @ Роджеріо і @ Пангейа. Це може бути хорошим прикладом для введення конструктора, але не є гарною відповіддю на початкове запитання. IoC, як визначено Фаулером , може бути реалізований без використання ін'єкцій будь-якого типу, наприклад, за допомогою сервісного локатора або навіть простого успадкування.
mtsz

642

Інверсія управління - це те, що ви отримуєте при відкликанні програми, наприклад, як програма gui.

Наприклад, у старому шкільному меню ви можете мати:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

тим самим контролюючи потік взаємодії користувачів.

У програмі GUI або щось подібне ми говоримо:

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

Отже, тепер управління перевернуто ... замість того, щоб комп'ютер приймав користувацькі введення у фіксованому порядку, користувач контролює порядок введення даних та коли дані зберігаються в базі даних.

В основному все , що має цикл подій, зворотний виклик або виконує тригери, належить до цієї категорії.


161
не позначайте цього хлопця. технічно він правильний martinfowler.com/bliki/InversionOfControl.html IoC є дуже загальним принципом. Потік управління "інвертується" введенням залежності, оскільки ви ефективно делегували залежності на якусь зовнішню систему (наприклад, контейнер IoC)
Jack Ukleja

38
Погодився з коментарем Шнайдера. 5 потік? Розум хизується, оскільки це єдина відповідь, яка справді правильна. Зверніть увагу на відкриття: " як програма gui". Ін'єкційна залежність - це лише найчастіше зустрічається реалізація IoC.
Jeff Sternal

40
Дійсно, це один з небагатьох правильних шанувальників! Хлопці, IoC принципово не стосується залежностей. Зовсім ні.
Rogério

13
+1 - Це хороший опис (з прикладом) наступного висловлювання Мартіна Фаулера - "Ранні користувацькі інтерфейси контролювали прикладну програму. У вас була б послідовність команд типу" Введіть ім'я "," Введіть адресу "; програма буде керувати підказками і отримувати відповідь на кожен. За допомогою графічних (або навіть на екрані) інтерфейсів UI рамки містили б цей основний цикл, а ваша програма замість цього забезпечувала обробники подій для різних полів на екрані. програма була перевернута, віддалена від вас до рамки ".
Ашиш Гупта

14
Тепер я розумію, чому його іноді пильно називають "Голлівудським принципом: не дзвоніть нам, ми зателефонуємо вам"
Олександр Сурафель

419

Що таке інверсія управління?

Якщо дотримуватися цих простих двох кроків, ви зробили інверсію управління:

  1. Відокремте, що частина - щоб зробити частина, коли - частина.
  2. Переконайтеся в тому, що , коли частина знає , як Літтл , як можна про який частини; і навпаки.

Для кожного з цих кроків можливе декілька методів на основі технології / мови, яку ви використовуєте для своєї реалізації.

-

Інверсія частина Инверсии управління (IoC) є заплутаною річчю; тому що інверсія - відносний термін. Найкращий спосіб зрозуміти IoC - забути про це слово!

-

Приклади

  • Обробка подій. Обробники подій (частина "що робити") - підвищення подій (частина "коли робити")
  • Інтерфейси. Клієнт-компонент (частина "коли робити") - реалізація компонентного інтерфейсу (частина "що робити")
  • xUnit кріплення. Налаштування та TearDown (частина того, що робити) - фреймворки xUnit викликають програму Setup на початку та TearDown в кінці (частина, яку потрібно робити)
  • Шаблон методу дизайну шаблону. метод шаблону, коли частина до виконання - реалізація примітивного підкласу частина що робити
  • Методи контейнерів DLL в COM. DllMain, DllCanUnload та ін. (Частина що робити) - COM / OS (частина, коли робити)

Як ви говорите Інтерфейси. Клієнт-компонент (частина "для виконання") як "коли" не має сенсу, коли ми використовуємо інтерфейси (напр .: введення залежностей), ми просто абстрагуємо його та надаємо клієнтові гнучкість щодо додавання будь-якої реалізації, але немає "коли" залучені туди. Я погоджуюсь з "коли" у випадку підвищення подій, що стосуються подій.
OldSchool

Під «компонентним клієнтом» я мав на увазі користувача / клієнта інтерфейсу. Клієнт знає "коли", щоб запустити частину "що робити", чи має намір розширити функціональність чи ні.
рпаттабі

Погляньте на цю чудову статтю Мартіна Фаулера. Він показує, як інтерфейси складають фундаментальну частину інверсії контролю: martinfowler.com/articles/injection.html#InversionOfControl
rpattabi

два перші речення - блискучі. приголомшливий !! ідеальне розділення коли робити і що робити !! Я не знаю, чому інші відповіді отримують стільки грошей. вони просто говорять коди без будь-якого розуміння.
Амір Зіараті

2
Мені подобається пояснення what-to-doіwhen-to-do
KimchiMan

164

Інверсія управління - це розділення проблем.

Без IoC : у вас портативний комп'ютер, і ви випадково зламаєте екран. І чорт, ви знайдете той же екран екрана ноутбука ніде на ринку. Так ти застряг.

За допомогою IoC : у вас настільний комп'ютер, і ви випадково зламаєте екран. Ви виявите, що можете просто захопити практично будь-який настільний монітор з ринку, і він добре працює з вашим робочим столом.

У цьому випадку ваш робочий стіл успішно реалізує IoC. Він приймає різні типи моніторів, тоді як ноутбук цього не робить, йому потрібен певний екран, щоб виправитись.


1
@Luo Jiong Hui Приємне пояснення.
Сачин

3
Більшість моделей дизайну, якщо не всі, мають у своєму повсякденному житті аналогів, які ми так добре бачимо та розуміємо. Найефективніший спосіб зрозуміти модель дизайну - це знати їх колеги в повсякденному житті. І я вірю, що їх багато.
Luo Jiong Hui

6
Неправильна відповідь. Ви пояснюєте введення залежності, а не ІОК. Дивіться коментар
Роджеріо

2
Я згоден. Це DI, а не IoC. Все ще отримує репутацію, оскільки це простий підхід, але допомагає розширити розуміння теми.
MAR

Це пояснює ін'єкційну залежність. Не Іок. Але приємне і чітке пояснення.
Chamin Wickramarathna

120

Інверсія контролю (або IoC) - це отримання свободи (Ви одружуєтеся, втратили свободу і вас контролюють. Ви розлучилися, ви щойно запровадили Інверсію контролю. Ось, що ми назвали, "розв'язали". Гарна комп'ютерна система перешкоджає дуже близьким стосункам.) Більше гнучкості (На кухні у вашому офісі подається лише чиста вода з-під крана, це ваш єдиний вибір, коли ви хочете пити. Ваш начальник впровадив Інверсію управління, встановивши нову кавоварку. Тепер ви отримаєте гнучкість вибору води або кави.) та менша залежність (У вашого партнера є робота, у вас немає роботи, ви фінансово залежите від свого партнера, тому ви контролюєте. Ви знайдете роботу, впровадили Інверсію контролю. Гарна комп'ютерна система заохочує залежність.)

Використовуючи настільний комп'ютер, ви невільницю (або скажімо, керуєте). Ви повинні сісти перед екраном і подивитися на нього. Використання клавіатури для набору та використання миші для навігації. І погано написане програмне забезпечення може невільнити вас ще більше. Якщо ви заміните робочий стіл ноутбуком, то ви дещо перевернули управління. Ви можете легко взяти його і пересуватися. Тож тепер ви можете контролювати, де ви знаходитесь зі своїм комп’ютером, замість того, щоб комп'ютер керував ним.

Реалізуючи Inversion of Control, споживач програмного забезпечення / об’єктів отримує більше елементів керування / опцій над програмним забезпеченням / об'єктами, замість того, щоб контролюватись або мати менше можливостей.

Маючи на увазі вищезазначені ідеї. Ми все ще пропускаємо ключову частину IoC. У сценарії IoC споживач програмного забезпечення / об'єктів - це складні рамки. Це означає, що створений вами код не називається самим. Тепер пояснимо, чому цей спосіб працює краще для веб-програми.

Припустимо, ваш код - це група працівників. Їм потрібно побудувати автомобіль. Ці працівники потребують місця та інструментів (програмного забезпечення) для побудови машини. Традиційні рамки програмного забезпечення будуть як гараж з великою кількістю інструментів. Тож робітники повинні скласти план самостійно і використовувати інструменти для побудови машини. Побудувати автомобіль - справа непроста, працівникам буде дуже важко планувати та співпрацювати належним чином. сучаснийПрограмне забезпечення буде подібне до сучасного автомобільного заводу зі всіма зручностями та менеджерами. Робітники не повинні складати ніякого плану, менеджери (частина рамки, вони найрозумніші люди і склали найскладніший план) допоможуть скоординуватись, щоб працівники знали, коли робити свою роботу (фреймворк називає ваш код). Працівники просто повинні бути досить гнучкими, щоб користуватися будь-якими інструментами, які надають їм менеджери (за допомогою ін'єкції залежності).

Хоча робітники надають управління управлінням проектом на найвищому рівні менеджерам (рамки). Але добре, щоб допомогли деякі професіонали. Це ідея ІОК по-справжньому походить.

Сучасні веб-додатки з архітектурою MVC залежать від основи для маршрутизації URL-адрес та встановлення контролерів на місце для виклику фреймворку.

Заливання залежності та інверсія управління пов'язані. Інжекція залежностей знаходиться на мікрорівні, а інверсія управління - на макрорівні . Ви повинні з'їсти кожен шматочок (реалізуйте DI), щоб закінчити їжу (реалізуйте IoC).


21
Я проголосував за порівняння DI до шлюбу та IoC до розлучення.
Marek Bar

"Хоча робітники надають керівництво управлінням проектом на найвищому рівні менеджерам (рамки). Але добре, щоб допомогли деякі професіонали. Це концепція ІОК по-справжньому походить". - По-перше, контроль є з менеджером. Чи можете ви пояснити, як перекручено цей елемент керування? За допомогою професіоналів (що це за професіонал)? Як?
Істіак Ахмед

@Istiaque Ахмед, порівнюючи гараж, де працівники мають повний контроль над усім, менеджери сучасного автозаводу контролюють виробництво. Тож зараз робітників контролюють, а не контролюють. Будьте в курсі, менеджери в цьому контексті є частиною сучасного автомобільного заводу, а не частиною працівників. Професіонали - це менеджери, які професійно займаються плануванням та виготовленням автомобілів.
Luo Jiong Hui

2
Повідомлення одружених людей: не розлучайтесь зараз, на заняттях з вашими дітьми також може застосовуватися IoC.
Джуліан

Так, це
єдине

94

Перш ніж використовувати Inversion of Control, ви повинні добре знати, що він має свої плюси і мінуси, і ви повинні знати, для чого ви його використовуєте, якщо це робите.

Плюси:

  • Ваш код роз’єднується, тому ви можете легко обмінюватися реалізаціями інтерфейсу з альтернативними реалізаціями
  • Це сильний мотиватор кодування проти інтерфейсів замість реалізацій
  • Писати одиничні тести для вашого коду дуже просто, оскільки це залежить не від нічого іншого, ніж від об'єктів, які він приймає у своєму конструкторі / сеттері, і ви можете легко ініціалізувати їх з потрібними об'єктами ізольовано.

Мінуси:

  • IoC не тільки інвертує керуючий потік у вашій програмі, але й значно затуманює його. Це означає, що ви більше не можете просто читати свій код і переходити з одного місця в інше, тому що з'єднання, які зазвичай є у вашому коді, більше не містяться в коді. Натомість це файли конфігурації XML або примітки та код вашого контейнера IoC, який інтерпретує ці метадані.
  • Виникає новий клас помилок, коли ви неправильно конфігуруєте XML або ваші анотації, і ви можете витратити багато часу, з'ясовуючи, чому ваш контейнер IoC вводить нульову посилання в один із ваших об'єктів за певних умов.

Особисто я бачу сильні моменти IoC, і мені вони дуже подобаються, але я схильний уникати IoC, коли це можливо, тому що це перетворює ваше програмне забезпечення в колекцію класів, які вже не становлять "справжню" програму, а просто щось, що потрібно скласти разом Конфігурація XML або метадані анотацій, і без них розпадаються (і розпадаються).


3
Перший кон невірний. В ідеалі у вашому коді повинно бути лише 1 контейнер МОК, і це ваш основний метод. Все інше повинно каскадувати звідти
mwjackson

23
Я думаю, що він має на увазі, ви не можете просто прочитати: myService.DoSomething () і перейти до визначення DoSomething, тому що з IoC, myService - це лише інтерфейс, і реальна реалізація вам не відома, якщо ви не підете шукати це в конфігураційних файлах xml або в основному методі, де налаштований ваш ioc.
chrizay

7
Саме тут допомагає Resharper - "натиснути перейти до реалізації" проти інтерфейсу. Уникнення IoC (а точніше, DI з вашого прикладу), ймовірно, також означає, що ви не тестуєте належним чином
IThasTheAnswer

10
Re: це перетворює ваше програмне забезпечення на набір класів, які вже не становлять "справжню" програму, а просто те, що потрібно скласти за допомогою конфігурації XML або метаданих анотацій і розпадеться (і розвалиться) без неї - я думаю, це дуже вводить в оману. Те саме можна сказати про будь-яку програму, написану поверх рамки. Різниця з хорошим контейнером IoC полягає в тому, що ви повинні мати можливість, якщо ваша програма добре розроблена та написана, вийняти її та виплеснути в інший з мінімальними змінами вашого коду, або викинути IoC взагалі та сконструювати об’єкти вручну. .
Ведмедик Овен

7
Приємно бачити відповідь у реальному світі, як це! Я думаю, що є багато досвідчених програмістів, зручних для об'єктно-орієнтованого дизайну та практик TDD, які вже використовують інтерфейси, фабричні зразки, моделі, керовані подіями, і глузують там, де це має сенс, перш ніж було винайдено цей модник "IoC". На жаль, занадто багато розробників / "архітекторів" заявляють про погану практику, якщо ви не користуєтесь їх бажаними рамками. Я віддаю перевагу кращому дизайну, використанню вбудованих мовних концепцій та інструментів, щоб досягти тієї самої мети з часткою складності, тобто без «помутніння» реалізації, як ви кажете :-)
Tony Wall

68
  1. Стаття у Вікіпедії . Для мене інверсія управління перетворює ваш послідовно написаний код і перетворює його в структуру делегування. Замість того, щоб ваша програма явно контролювала все, ваша програма встановлює клас або бібліотеку з певними функціями, які потрібно викликати, коли відбуваються певні речі.

  2. Він вирішує дублювання коду. Наприклад, за старих часів ви вручну писали б свій власний цикл подій, оглядаючи системні бібліотеки для нових подій. На сьогоднішній день у більшості сучасних API ви просто повідомляєте системним бібліотекам, які події вас цікавлять, і вони повідомлять вас про те, коли вони відбудуться.

  3. Інверсія управління - це практичний спосіб зменшити дублювання коду, і якщо ви виявите, що копіюєте цілий метод і змінюєте лише невеликий фрагмент коду, ви можете розглянути можливість його боротьби з інверсією управління. Інверсія управління полегшується багатьма мовами завдяки концепції делегатів, інтерфейсів чи навіть необроблених покажчиків функцій.

    Використовувати його не доцільно у всіх випадках, оскільки за потоком програми може бути важче прослідкувати, коли написано таким чином. Це корисний спосіб проектування методів при написанні бібліотеки, яка буде повторно використана, але її слід використовувати ощадливо в основі вашої власної програми, якщо це дійсно не вирішує проблему дублювання коду.


37
Я вважаю, що стаття у Вікіпедії дуже заплутана і потребує виправлення. Перегляньте сторінку обговорення для сміху.
devios1

Написання власного циклу подій все ще може бути інверсією контролю, якщо цей цикл подій займає місце фреймворку, а решта коду використовує принцип IoC, який ви тільки що написали власну структуру. Це насправді не погано, це збільшує читабельність ціною лише трохи більше кодування (не те, що завжди доречно).
lijat

45

Але я думаю, що ви повинні бути дуже обережні з цим. Якщо ви зловживаєте цим шаблоном, ви зробите дуже складний дизайн і ще складніший код.

Як у цьому прикладі з TextEditor: якщо у вас є лише один SpellChecker, можливо, це не дуже потрібно використовувати IoC? Якщо вам не потрібно писати одиничні тести чи щось таке ...

У будь-якому випадку: будьте розумні. Модель дизайну - це добра практика, але не Біблія, яку слід проповідувати. Не скріплюйте його скрізь.


3
Звідки ви знаєте, що у вас буде лише одна перевірка орфографії?
Простежте

@ Trace Ви могли знати, як програма, яку ви збираєтеся писати, звикне, наприклад. Однак деякі методи, такі як ін'єкція залежності, настільки дешеві, що рідко є причина не використовувати їх у такому випадку.
lijat

44

IoC / DI для мене витісняє залежність від об'єктів, що викликають. Супер просто.

Відповідь, що не займається технікою, зможе поміняти двигун в машині безпосередньо перед тим, як увімкнути його. Якщо все підходить правильно (інтерфейс), ви добре.


44

Припустимо, ти об’єкт. І ти йдеш у ресторан:

Без IoC : ви просите "яблуко", і вам завжди подають яблуко, коли ви просите більше.

З IoC : Ви можете попросити "фрукти". Ви можете отримувати різні фрукти щоразу, коли вас подають. наприклад, яблуко, апельсин або кавун.

Тому, очевидно, IoC вважається кращим, коли вам подобаються сорти.


26
  1. Інверсія управління - це схема, яка використовується для роз'єднання компонентів і шарів у системі. Шаблон реалізується за допомогою введення залежностей у компонент при його побудові. Ці залежності, як правило, надаються як інтерфейси для подальшої розв'язки та для підтвердження тестабельності. Контейнери IoC / DI, такі як Castle Windsor, Unity - це інструменти (бібліотеки), які можна використовувати для надання IoC. Ці інструменти надають розширені можливості вище та поза простим управлінням залежностями, включаючи термін експлуатації, AOP / перехоплення, політику тощо.

  2. а. Звільняє компонент від відповідальності за управління його залежностями.
    б. Надає можливість міняти реалізацією залежностей у різних середовищах.
    c. Дозволяє перевірити компонент через глузування залежностей.
    г. Забезпечує механізм обміну ресурсами протягом програми.

  3. а. Критично важливо робити тестові розробки. Без IoC це може бути важко перевірити, оскільки тестовані компоненти сильно поєднані з рештою системи.
    б. Критичний при розробці модульних систем. Модульна система - це система, компоненти якої можна замінити, не вимагаючи перекомпіляції.
    c. Критично важливо, якщо є багато наскрізних проблем, з якими потрібно вирішити, зокрема, у корпоративній програмі.


2
Насправді, ІОК в основному не стосується управління залежностями. Будь ласка, ознайомтеся з martinfowler.com/articles/injection.html#InversionOfControl Зокрема, зверніть увагу на частину, яка говорить "Інверсія контролю є надто загальним терміном, і, таким чином, люди вважають його заплутаним. В результаті багато дискусій з різними захисниками IoC ми визначається назвою введення залежності ".
Rogério

26

Відповідаючи лише на першу частину. Що це?

Інверсія управління (IoC) означає створити екземпляри залежностей першого та останнього примірника класу (необов'язково вводити їх через конструктор), а не створювати спочатку екземпляр класу, а потім екземпляр класу, створюючи екземпляри залежностей. Таким чином, інверсія управління інвертує на потік управління програми. Замість того , щоб на викликається керуючому в потік управління (при створенні залежностей), то абонент контролює потік управління програми .



22

Я запишу своє просте розуміння цих двох термінів:

For quick understanding just read examples*

Ін'єкція залежностей (DI):
Ін'єкція залежності залежить, як правило, проходження об'єкта, від якого метод залежить як параметр методу, а не метод, який створює залежний об'єкт .
На практиці це означає, що метод не залежить безпосередньо від конкретної реалізації; будь-яка реалізація, яка відповідає вимогам, може передаватися як параметр.

За допомогою цього об'єкти повідомляють про свої залежності. А весна робить її доступною.
Це призводить до слабко пов'язаної розробки додатків.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,
              IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
   (if address is defines as dependency by Employee object)

Контейнер інверсії управління (IoC):
Це загальна характеристика рамок, МОК управляє об'єктами java
- від інстанції до знищення через його BeanFactory.
-Java компоненти, які інстанціюються контейнером IoC, називають квасолею, а контейнер IoC керує сферою дії квасолі, подіями життєвого циклу та будь-якими функціями AOP, для яких він був налаштований та кодований.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it.

Реалізуючи Inversion of Control, споживач програмного забезпечення / об’єктів отримує більше елементів керування / опцій над програмним забезпеченням / об'єктами, замість того, щоб контролюватись або мати менше можливостей.

Інверсія управління як настанова проектування служить наступним цілям:

Відбувається роз'єднання виконання певного завдання від реалізації.
Кожен модуль може зосередитись на тому, для чого він призначений.
Модулі не передбачають припущень щодо того, що роблять інші системи, але покладаються на їх контракти.
Заміна модулів не побічно впливає на інші модулі.
Я буду тримати абстрактні речі тут. Ви можете перейти за наступними посиланнями для детального розуміння теми.
Гарне прочитання з прикладом

Детальне пояснення


17

Я погоджуюся з NilObject , але я хотів би додати до цього:

якщо ви виявите, що копіюєте весь метод і змінюєте лише невеликий фрагмент коду, ви можете розглянути питання щодо його інверсії управління

Якщо ви виявляєте, що копіюєте та вставляєте код навколо, ви майже завжди робите щось не так. Кодифікований як принцип дизайну Раз і тільки один раз .


17

Наприклад, завдання №1 - створити об’єкт. Без концепції МОК завдання №1 має бути виконано програмістом. Але з концепцією МОК завдання №1 буде виконано контейнером.

Коротше кажучи, управління перетворюється з програміста на контейнер. Отже, це називається інверсією управління.

Я знайшов один хороший приклад тут .


Контейнер - це поняття в IoC, де об'єктна модель, що включає залежності (відносини між "користувачем" об'єктом та "використовуваним" об'єктом) і об'єктами, розміщується та керується - наприклад, міститься. Контейнер зазвичай забезпечується рамкою IoC, наприклад Spring. Подумайте про це як сховище виконання об'єктів, що складають вашу програму.
Ведмедик Овен

17

Скажімо, що ми проводимо зустріч у якомусь готелі.

Багато людей, багато кафе, води, багато пластикових стаканчиків.

Коли хтось хоче пити, вона наповнює чашку, п’є і кидає чашку на підлогу.

Через годину чи щось у нас є підлога, покрита пластиковими чашками та водою.

Нехай інвертне управління.

Ту ж зустріч там же, але замість пластикових чашок у нас є офіціант із однією скляною чашкою (Singleton)

і вона весь час пропонує гостям пити.

Коли хтось хоче пити, вона дістає зі стакана офіціанта, випиває і повертає назад офіціанту.

Залишаючи осторонь питання про гігієнічну, остання форма контролю питного процесу набагато ефективніша та економічна.

І саме це робить Spring (інший контейнер IoC, наприклад: Guice). Замість того, щоб дозволити додатку створювати все необхідне, використовуючи нове ключове слово (беручи пластикову чашку), контейнер Spring IoC весь час пропонує застосувати той же екземпляр (синглтон) необхідного предмета (склянку води).

Подумайте про себе як про організатора такої зустрічі. Вам потрібен спосіб повідомлення адміністрації готелю про це

Учасникам зборів знадобиться стакан води, але не шматок пирога.

Приклад: -

public class MeetingMember {

    private GlassOfWater glassOfWater;

    ...

    public void setGlassOfWater(GlassOfWater glassOfWater){
        this.glassOfWater = glassOfWater;
    }
    //your glassOfWater object initialized and ready to use...
    //spring IoC  called setGlassOfWater method itself in order to
    //offer to meetingMember glassOfWater instance

}

Корисні посилання:-


не є одиночними об'єктами статичного типу?
Gokigooooks

16

Здається, що найбільш заплутане в абревіатурі "IoC" та назві, за якою вона стоїть, - це те, що це занадто гламурне ім'я - майже шумне ім'я.

Чи справді нам потрібна назва, за допомогою якої можна описати різницю між процедурним та подійним програмуванням? Гаразд, якщо нам потрібно, але чи потрібно вибирати нове ім’я "більше, ніж життя", яке більше бентежить, ніж вирішує?


1
IoC! = Керована подіями. Подібність (а в деяких випадках і збігається), але вони принципово не є однаковою парадигмою.
Ведмедик Аунрі

Хороше питання. Програмування на основі подій - це, безумовно, IoC. Ми пишемо обробники подій, і вони дзвонять з циклу подій. Але IoC є більш загальною концепцією, ніж програмування, кероване подіями. Якщо ви перекриєте метод підкласу, він також є своєрідним IoC. Ви пишете код, до якого буде викликано відповідний посилання (екземпляр).
vi.su.

15

Інверсія контролю - це коли ти йдеш до продуктового магазину, а дружина дає тобі список продуктів, які можна придбати.

З точки зору програмування, вона передала функцію зворотного виклику функції, getProductList()яку ви виконуєте - doShopping().

Це дозволяє користувачеві функції визначати деякі його частини, роблячи її більш гнучкою.


5
Моя дружина зазвичай магазини зі мною, але я згоден з цим твердженням.
ha9u63ar

1
@ ha9u63ar Ваша дружина покуповує з вами? Ну, це називається агрегація.
Джуліан

2
Якщо вона також дає гроші, це називається DI.
Сан-

1
Слово Інверсія - догори ногами - походить від того, коли дружина дзвонить getProductList()вам, щоб знайти джерело грошей, означає, що контроль у вас поруч. У випадку інверсії, яку вона контролюватиме, значить, гроші, які вона надасть, щоб придбати.
Сан-

13

Я знайшов дуже яскравий приклад тут , який пояснює , як "контроль інвертується.

Класичний код (без введення залежності)

Ось як приблизно буде працювати код, що не використовує DI:

  • Додаток потребує Foo (наприклад, контролер), так що:
  • Додаток створює Foo
  • Додаток викликає Foo
    • Foo потрібен бар (наприклад, послуга), так що:
    • Foo створює Бар
    • Фу дзвонить Бар
      • Бару потрібен Bim (сервіс, сховище, ...), так що:
      • Бар створює Бім
      • Бар щось робить

Використання ін'єкції залежності

Ось як приблизно буде працювати код з використанням DI:

  • Додаток потребує Foo, який потребує Bar, якому потрібен Bim, так що:
  • Додаток створює Bim
  • Додаток створює Бар і надає йому Бім
  • Додаток створює Foo і надає йому бар
  • Додаток викликає Foo
    • Фу дзвонить Бар
      • Бар щось робить

Контроль залежностей перевернуто від одного виклику до виклику.

Які проблеми вона вирішує?

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

Напр .: Припустимо, що ваша програма зберігає завантажений користувачем файл на Диску Google, з DI ваш код контролера може виглядати так:

class SomeController
{
    private $storage;

    function __construct(StorageServiceInterface $storage)
    {
        $this->storage = $storage;
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

class GoogleDriveService implements StorageServiceInterface
{
    public function authenticate($user) {}
    public function putFile($file) {}
    public function getFile($file) {}
}

Коли ваші вимоги змінюються, замість GoogleDrive вас попросять використовувати Dropbox. Вам потрібно лише написати реалізацію папки для інтерфейсу StorageServiceInterface. Ви не вносите жодних змін у контролер до тих пір, поки реалізація Dropbox дотримується інтерфейсу StorageServiceInterface.

Під час тестування ви можете створити макет для StorageServiceInterface за допомогою макетної реалізації, де всі методи повертають нульове значення (або будь-яке заздалегідь визначене значення відповідно до вашої вимоги тестування).

Натомість, якщо у вас був клас контролера, щоб сконструювати об’єкт зберігання з таким newключовим словом:

class SomeController
{
    private $storage;

    function __construct()
    {
        $this->storage = new GoogleDriveService();
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

Коли ви хочете змінитись із реалізацією Dropbox, вам доведеться замінити всі рядки, де newпобудований об’єкт GoogleDriveService, і використовувати DropboxService. Крім того, під час тестування класу SomeController конструктор завжди очікує, що клас GoogleDriveService і справжні методи цього класу запускаються.

Коли це доречно і коли ні? На мою думку, ти використовуєш DI, коли думаєш, що існують (або можуть бути) альтернативні реалізації класу.


Це має бути найбільш правильною відповіддю, оскільки єдиний пояснює, як перевертається "контроль".
Ярімадам

найкраще пояснення поки що
Ali80

12

Тут можна знайти дуже просте письмове пояснення

http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html

Він говорить -

"Будь-яке нетривіальне додаток складається з двох або більше класів, які співпрацюють один з одним для виконання певної логіки бізнесу. Традиційно кожен об'єкт відповідає за отримання власних посилань на об'єкти, з якими співпрацює (його залежності). Об'єкти дають свої залежності на час створення деяким зовнішнім об'єктом, який координує кожен об'єкт у системі. Іншими словами, залежності вводяться в об'єкти ".


12

Інверсія управління є загальним принципом, в той час як залежність введення реалізує цей принцип як модель дизайну для побудови графіків об'єкта (тобто конфігурація контролює те, як об'єкти посилаються один на одного, а не сам об'єкт, який контролює, як отримати посилання на інший об'єкт).

Дивлячись на Інверсію управління як на модель дизайну, нам потрібно подивитися, що ми перетворюємо. Залежність впорскування інвертує управління побудовою графіка об'єктів. Якщо сказати терміном непростого, інверсія управління передбачає зміну потоку управління в програмі. Напр. У традиційному автономному додатку у нас є основний метод, з якого управління передається іншим стороннім бібліотекам (на випадок, якщо ми використали функцію сторонньої бібліотеки), але через інверсію управління керуванням передається з коду бібліотеки третьої сторони до нашого коду , оскільки ми приймаємо послугу бібліотеки третьої сторони. Але є й інші аспекти, які потрібно перевернути в межах програми - наприклад, виклик методів і потоків для виконання коду.

Для тих, хто цікавиться більшою глибиною Inversion of Control, був опублікований документ, в якому викладена більш повна картина Інверсії управління як структури дизайну (OfficeFloor: використання шаблонів офісу для вдосконалення дизайну програмного забезпечення http://doi.acm.org/10.1145/ 2739011.2739013 з безкоштовною копією, доступною для завантаження з http://www.officefloor.net/about.html ).

Виявлено наступні відносини:

Інверсія управління (для методів) = залежність (стан) впорскування + продовження впорскування + впорскування нитки

Підсумок вищезазначених взаємозв'язків щодо інверсії управління доступний - http://dzone.com/articles/inversion-of-coupling-control


Це дуже чітка відповідь. Дякую за пояснення.
КуньЮ Цай

11

IoC полягає в інвертуванні зв'язку між вашим кодом та стороннім кодом (бібліотека / фреймворк):

  • При нормальній розробці s / w ви пишете основний () метод і викликаєте "бібліотечні" методи. Ви керуєте :)
  • В IoC "фреймворк" керує main () і називає ваші методи. Framework контролює :(

DI (залежність впорскування) - це про те, як управління протікає в додатку. Традиційна програма для настільних ПК мала контрольний потік від вашої програми (основного () методу) до інших викликів методів бібліотеки, але, якщо потік управління DI інвертований, цей фреймворк дбає про запуск програми, ініціалізацію його та виклик ваших методів, коли потрібно.

Зрештою, ви завжди виграєте :)


10

Мені подобається це пояснення: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

Вона починається просто і показує також приклади коду.

введіть тут опис зображення

Споживачеві X потрібен споживаний клас Y для досягнення чогось. Це все добре і природно, але чи справді X потрібно знати, що він використовує Y?

Хіба недостатньо того, що X знає, що він використовує те, що має поведінку, методи, властивості тощо, Y, не знаючи, хто реально реалізує поведінку?

Витягуючи абстрактне визначення поведінки, яке використовує X у Y, проілюстроване як I нижче, і дозволяючи споживачеві X використовувати екземпляр цього замість Y, він може продовжувати робити те, що робить, не знаючи особливостей Y.

введіть тут опис зображення

На наведеній вище ілюстрації Y реалізує I і X використовує екземпляр I. Хоча цілком можливо, що X все ще використовує Y, що цікаво, це те, що X цього не знає. Він просто знає, що використовує щось, що реалізує я.

Прочитайте статтю для отримання додаткової інформації та опису переваг, таких як:

  • X вже не залежить від Y
  • Більш гнучка, реалізація може бути вирішена під час виконання
  • Ізоляція блоку коду, простіше тестування

...


Посилання дуже корисно. Дійсно дякую :)
M Fuat NUROĞLU

10

Я розумію, що тут вже була дана відповідь. Але я все-таки думаю, що деякі основи щодо інверсії управління повинні бути обговорені тут для майбутніх читачів.

Інверсія управління (IoC) була побудована за дуже простим принципом під назвою Голівудський принцип . І це говорить про те,

Не дзвоніть нам, ми зателефонуємо вам

Це означає, що не їдьте в Голлівуд, щоб здійснити свою мрію, а якщо ви гідні, то Голлівуд знайде вас і здійснить вашу мрію. Досить перевернута, так?

Тепер, коли ми обговорюємо принцип ІОК, ми забуваємо про Голлівуд. Для IoC повинно бути три стихії, голлівудський, ти і таке завдання, як виконати свою мрію.

У нашому світі програмування Голлівуд представляє собою загальну основу (може бути написана вами чи ким-небудь іншим), ви представляєте код користувача, який ви написали, а завдання представляють те, що ви хочете виконати зі своїм кодом. Тепер ви ніколи не ходите самостійно запускати завдання, а не в IoC! Швидше ви створили все так, щоб ваша рамка викликала ваше завдання. Таким чином, ви створили основу для багаторазового використання, яка може зробити когось героєм чи іншим лиходієм. Але ця основа завжди відповідає, вона знає, коли когось обрати, і хтось знає лише те, що хоче бути.

Тут можна навести приклад із реального життя. Припустимо, ви хочете розробити веб-додаток. Отже, ви створюєте рамку, яка буде обробляти всі звичайні речі, якими має працювати веб-додаток, як обробка http-запиту, створення меню програми, сервірування сторінок, керування файлами cookie, запуск подій тощо.

І тоді ви залишаєте кілька гачків у вашій рамці, куди ви можете помістити подальші коди для створення користувацького меню, сторінок, файлів cookie або реєстрації деяких подій користувача тощо. На кожен запит браузера ваша рамка запускається та виконує ваші користувацькі коди, якщо підключена, потім обслуговуватиме її назад до браузера.

Отже, ідея досить проста. Замість того, щоб створювати користувальницьку програму, яка контролюватиме все, спочатку ви створюєте багаторазовий фреймворк, який контролюватиме все, потім записуйте власні коди та підключаєте їх до рамки, щоб виконати ці вчасно.

Laravel та EJB - приклади таких рамок.

Довідка:

https://martinfowler.com/bliki/InversionOfControl.html

https://en.wikipedia.org/wiki/Inversion_of_control


1
Найбільш відповідну відповідь я знайшов тут.
blueray

8

Програмування говоріння

IoC у простому розумінні: це використання Інтерфейсу як способу конкретного чогось (такого поля чи параметра) як підстановочного символу, який може використовуватися деякими класами. Це дозволяє повторно використовувати код.

Наприклад, скажімо, що у нас є два класи: Собака та Кішка . Обидва мають однакові якості / стани: вік, розмір, вага. Тож замість створення класу сервісів, який називається DogService та CatService , я можу створити єдиний під назвою AnimalService, який дозволяє використовувати собак і кішок, лише якщо вони використовують інтерфейс IAnimal .

Однак, прагматично кажучи, це має певний зворотній бік.

a) Більшість розробників не знають, як ним користуватися . Наприклад, я можу створити клас під назвою Customer і я можу автоматично створити (за допомогою інструментів IDE) інтерфейс під назвою ICustomer . Отже, не рідко можна знайти папку, наповнену класами та інтерфейсами, незалежно від того, будуть використані інтерфейси чи ні. Це називається БЛОТОВАНО. Деякі люди можуть стверджувати, що "можливо, у майбутньому ми можемо ним скористатися". : - |

б) Він має деякі обмеження. Наприклад, поговоримо про випадок Собаки та Кішки, і я хочу додати нову послугу (функціональність) лише для собак. Скажімо, я хочу обчислити кількість днів, які мені потрібні для дресирування собаки ( trainDays()), для котів це марно, котів не можна тренувати (я жартую).

b.1) Якщо я додаю trainDays()до Service AnimalService, він також працює з кішками, і це зовсім не дійсно.

b.2) Я можу додати умову, в trainDays()якій він оцінює, який клас використовується. Але він повністю порушить IoC.

b.3) Я можу створити новий клас сервісу під назвою DogService лише для нового функціоналу. Але це збільшить ремонтопридатність коду, оскільки у нас буде два класи обслуговування (з подібною функціональністю) для Dog, і це погано.


Про роздуті класи / інтерфейси: Вам не завжди потрібно використовувати кожен інтерфейс. Іноді просто має сенс розділити великий інтерфейс на багато менших, щоб побачити його функціональні межі. Менші інтерфейси також простіше використовувати в інших реалізаціях. Також він заохочує вас кодувати до інтерфейсу, де це має сенс. Розглянемо "Інтерфейсна сегрегація". Тільки те, що ви використовуєте інтерфейс, не означає, що ви роз'єднані. Єдиний жировий інтерфейс марний. - Тільки мої 2 копійки :)
МК

7

Я прочитав багато відповідей на це, але якщо хтось все ще плутається і потребує плюс ультра "лайманського терміна", щоб пояснити IoC, ось мій:

Уявіть, що батько та дитина розмовляють між собою.

Без IoC:

* Батько : Ви можете говорити лише тоді, коли я задаю вам запитання, і ви можете діяти лише тоді, коли я даю вам дозвіл.

Батько : Це означає, що ви не можете запитати мене, чи можете ви їсти, грати, ходити до ванної кімнати чи навіть спати, якщо я вас не прошу.

Батько : Хочеш їсти?

Дитина : Ні.

Батько : Гаразд, я повернусь. Чекай на мене.

Дитина : (Хоче грати, але оскільки у батька питання не виникає, дитина нічого не може зробити).

Через 1 годину ...

Батько : Я повернувся. Ви хочете пограти?

Дитина : Так.

Батько : дозвіл надано.

Дитина : (нарешті вміє грати).

Цей простий сценарій пояснює, що управління зосереджено на батьківському. Свобода дитини обмежена і сильно залежить від питання батька. Дитина може ТОЛЬКО говорити, коли її просять говорити, і може ТІЛЬКИ діяти, коли вона отримала дозвіл.

З IoC:

Дитина тепер має можливість задавати питання, а батько може відповідати відповідями та дозволами. Просто означає, що управління перевернуто! Дитина тепер вільна задавати питання в будь-який час, і хоча існує ще залежність з батьком щодо дозволів, він не залежить від засобів говорити / задавати питання.

У технологічному способі пояснення це дуже схоже на взаємодію консолі / оболонки / cmd проти GUI. (Яка відповідь Марка Гаррісона вище № 2 верхньої відповіді). На консолі ви залежите від того, що вам запитують / показують, і ви не можете перейти до інших меню та функцій, не відповівши спочатку на це питання; дотримуючись суворого послідовного потоку. (програмно це як метод / цикл функцій). Однак із графічним інтерфейсом, меню та функції викладені, і користувач може вибирати все, що потрібно, тим самим маючи більше контролю та менше обмеження. (програмно, у меню є зворотний виклик, коли вибрано дію).


6

Інверсія управління стосується передачі контролю з бібліотеки клієнту. Це має більше сенсу, коли ми говоримо про клієнта, який вводить (передає) значення функції (лямбда-вираз) у функцію вищого порядку (бібліотечна функція), яка контролює (змінює) поведінку функції бібліотеки. Клієнт або структура, яка вводить залежність бібліотеки (яка несе поведінку), також може вважатися IoC


5

Оскільки відповідей на питання вже багато, але жоден з них не показує розбиття терміну управління інверсією, я бачу можливість дати більш коротку та корисну відповідь.

Інверсія управління - це схема, яка реалізує принцип інверсії залежності (DIP). DIP визначає наступне: 1. Модулі високого рівня не повинні залежати від модулів низького рівня. Обидва повинні залежати від абстракцій (наприклад, інтерфейсів). 2. Абстракції не повинні залежати від деталей. Деталі (конкретні реалізації) повинні залежати від абстракцій.

Існує три типи інверсії управління:

Постачальники інверсії інтерфейсу не повинні визначати інтерфейс. Натомість споживач повинен визначити інтерфейс, а постачальники повинні його реалізувати. Інверсія інтерфейсу дозволяє усунути необхідність змінювати споживача щоразу, коли додається новий постачальник.

Інверсія потоку Змінює контроль потоку. Наприклад, у вас є консольна програма, де ви попросили ввести багато параметрів, і після кожного введеного параметра ви змушені натискати Enter. Тут ви можете застосувати Flow Inversion і реалізувати настільний додаток, де користувач може вибрати послідовність введення параметрів, користувач може редагувати параметри, а на останньому кроці користувачеві потрібно натиснути Enter лише один раз.

Інверсія створення Це може бути реалізовано за такими шаблонами: Заводська модель, Локатор обслуговування та Введення залежностей. Інверсія створення допомагає усунути залежності між типами, що переміщують процес створення об'єктів залежності поза типом, який використовує ці об'єкти залежності. Чому залежності погані? Ось декілька прикладів: пряме створення нового об’єкта у вашому коді ускладнює тестування; неможливо змінити посилання в зборах без перекомпіляції (порушення принципу OCP); Ви не можете легко замінити інтерфейс робочого столу веб-інтерфейсом.


3
  1. Отже номер 1 вище . Що таке інверсія управління?

  2. Технічне обслуговування - це річ, яку вона вирішує для мене. Це гарантує, що я використовую інтерфейси, щоб два класи не були інтимними один з одним.

Використовуючи такий контейнер, як Castle Windsor, він ще краще вирішує проблеми з технічним обслуговуванням. Можливість замінити компонент, який переходить до бази даних, на той, який використовує стійкість на основі файлів без зміни рядка коду, дивовижний (зміна конфігурації, ви готові).

І як тільки ви потрапляєте в дженерики, він стає ще кращим. Уявіть, що у вас є видавець повідомлень, який приймає записи та публікує повідомлення. Не байдуже, що він публікує, але йому потрібен картограф, щоб взяти щось із запису до повідомлення.

public class MessagePublisher<RECORD,MESSAGE>
{
    public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
    {
      //setup
    }
}

Я писав це колись, але тепер я можу вводити багато типів у цей набір кодів, якщо публікую різні типи повідомлень. Я також можу написати картографи, які беруть запис одного типу, і відображають їх у різні повідомлення. Використання DI з Generics дало мені можливість написати дуже мало коду для виконання багатьох завдань.

О так, є проблеми, пов'язані зі встановленням безпеки, але вони є вторинними щодо переваг IoC / DI.

Я, безумовно, люблю IoC / DI.

3. Це стає більш підходящим з тієї хвилини, коли у вас є проект середнього розміру дещо більшої складності. Я б сказав, що це стає доречним, як тільки ти починаєш відчувати біль.



3

Створення об'єкта в класі називається герметичним з'єднанням, Spring усуває цю залежність, слідуючи схемі проектування (DI / IOC). У якому об'єкт класу передається в конструктор, а не створюється в класі. Більше ми надаємо контрольну змінну суперкласу в конструкторі для визначення більш загальної структури.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.