Dlaczego Inversion of Control ma taką nazwę?

98

Słowa invertlub controlwcale nie są używane do zdefiniowania Odwrócenia kontroli w definicjach, które widziałem.

Definicje

Wikipedia

Inwersja sterowania (IoC) jest techniką programowania, wyrażoną tutaj w kategoriach programowania obiektowego, w której sprzężenie obiektów jest powiązane w czasie wykonywania przez obiekt asemblera i zwykle nie jest znane w czasie kompilacji za pomocą analizy statycznej. ~ http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

Inwersja kontroli jest powszechnym wzorcem w społeczności Java, który pomaga łączyć lekkie pojemniki lub montować komponenty z różnych projektów w spójną aplikację. ~ na podstawie http://www.martinfowler.com/articles/injection.html (przeredagowany)


Dlaczego więc Inwersja kontroli nosi nazwę Inwersja kontroli? Jaka kontrola jest odwracana i przez co? Czy istnieje sposób, aby określić odwrócenie sterowania używając terminologii: inwertowany i kontrola ?

Korey Hinton
źródło
22
Rekwizyty dla osoby, która może to wyjaśnić prostym językiem angielskim.
Robert Harvey
2
Jeśli definicja używałaby słowa, które definiuje, byłaby to awaria słownika. Podobna logika obowiązuje tutaj.
Izkata
2
Zobacz także na StackOverflow: Co to jest odwrócenie kontroli?
Izkata
2
@Izkata, słowniki bardzo często definiują frazy w kategoriach własnych lub synonimów. tj .: siła definicji przyrody używa w swojej definicji słów siła i natura lub w definicji usługi używa się słów reguły i usługa, w których reguły są synonimem terminów.
Korey Hinton
3
Z tego właśnie powodu wolę używać terminu „automatyczne wstrzykiwanie zależności” lub ADI zamiast IoC; Sam Fowler wspomina, że ​​większość obecnych paradygmatów programistycznych ma swego rodzaju „odwrócenie kontroli”, przy czym termin ten jest ogólnie definiowany jako „ponowne przekazanie ustaleń kodu do wykonania i czasu, w którym należy go wykonać na zewnątrz system kontroli, gdy takie ustalenia są tradycyjnie dokonywane przez sam program ". Wszystko, od przerw sprzętowych po programowanie sterowane zdarzeniami, po maszyny wirtualne i wielozadaniowość dzieje się z IoC.
KeithS,

Odpowiedzi:

67

Załóżmy, że masz jakąś klasę „repozytorium” i że to repozytorium jest odpowiedzialne za przekazywanie danych ze źródła danych.

Repozytorium może samo nawiązać połączenie ze źródłem danych. Ale co, jeśli pozwoli ci przejść przez połączenie ze źródłem danych przez konstruktor repozytorium?

Umożliwiając abonentowi wywołującemu połączenie, odłączyłeś zależność połączenia źródła danych od klasy repozytorium, umożliwiając dowolne źródło danych do pracy z repozytorium, a nie tylko to, które określa repozytorium.

Zostały odwrócone sterowanie poprzez przekazanie odpowiedzialności ustanowieniem połączenia z repozytorium klasy do rozmówcy.

Martin Fowler sugeruje użycie terminu „wstrzykiwanie zależności”, aby opisać ten typ inwersji kontroli, ponieważ inwersja kontroli jako koncepcja może być stosowana szerzej niż tylko wstrzykiwanie zależności w metodzie konstruktora.

Robert Harvey
źródło
3
Jest to przykład wstrzykiwania zależności, ale wstrzykiwanie zależności jest tylko podzbiorem odwrócenia kontroli. Istnieją inne rzeczy całkowicie niezwiązane z iniekcją zależności, które ćwiczą odwracanie kontroli.
dsw88
1
@ mustang2009cobra: Dzięki. Przykładem jest to, czego szukałem, a nie wyczerpujący katalog przypadków, w których występuje, a termin „Inwersja kontroli” jest najbardziej kojarzony z DI, a nie z przekazywaniem wiadomości lub innymi podobnymi pojęciami.
Robert Harvey
To prawda, że ​​wstrzykiwanie zależności jest najbardziej rozpowszechnionym przykładem IoC, więc przykład DI ma sens. Być może niewielka zmiana w odpowiedzi, która wskazuje, że jest to przykład DI, który jest najbardziej widocznym rodzajem Internetu Rzeczy?
dsw88
1
Właśnie tego szukałem! Wiele przykładów i definicji IoC nie określa jednoznacznie, jaka kontrola jest odwrócona. Zdaję sobie sprawę, że w IoC może być coś więcej niż tylko zastrzyk uzależnienia, ale teraz coś w końcu kliknęło w moim mózgu. Dzięki!
Korey Hinton
79

Nie sądzę, aby ktokolwiek mógł to wyjaśnić lepiej niż Martin Fowler, w dalszej części artykułu, do którego linkujesz .

W przypadku tej nowej rasy kontenerów inwersja dotyczy sposobu wyszukiwania implementacji wtyczki. W moim naiwnym przykładzie lister sprawdził implementację wyszukiwarki, bezpośrednio ją tworząc. Dzięki temu wyszukiwarka nie jest wtyczką. Podejście stosowane przez te kontenery polega na zapewnieniu, że każdy użytkownik wtyczki postępuje zgodnie z pewną konwencją, która pozwala osobnemu modułowi asemblera na wstrzyknięcie implementacji do listera.

Jak wyjaśnia w powyższych akapitach, nie jest to dokładnie to samo, co powód, dla którego powstał termin „Odwrócenie kontroli”.

Kiedy te kontenery mówią o tym, jak są tak przydatne, ponieważ implementują „Inwersję kontroli”, jestem bardzo zdziwiony. Odwrócenie kontroli jest wspólną cechą ram, więc powiedzenie, że te lekkie kontenery są wyjątkowe, ponieważ używają odwrócenia kontroli, jest jak powiedzenie, że mój samochód jest wyjątkowy, ponieważ ma koła.

Pytanie, jaki aspekt kontroli odwracają? Kiedy po raz pierwszy wpadłem na odwrócenie kontroli, było to w głównej kontroli interfejsu użytkownika. Wczesne interfejsy użytkownika były kontrolowane przez aplikację. Będziesz miał sekwencję poleceń, takich jak „Wprowadź nazwę”, „wprowadź adres”; twój program wyświetlał monity i odbierał odpowiedzi na każde z nich. W przypadku graficznych (lub nawet ekranowych) interfejsów środowisko interfejsu użytkownika zawierałoby tę główną pętlę, a program zamiast tego zapewniał obsługę zdarzeń dla różnych pól na ekranie. Główna kontrola programu została odwrócona, przeniesiona z dala od ciebie do frameworka.

Dlatego kontynuuje określanie terminu „wstrzykiwanie zależności”, aby objąć tę konkretną implementację Inwersji Kontroli.

W rezultacie myślę, że potrzebujemy bardziej konkretnej nazwy dla tego wzoru. Odwrócenie kontroli jest zbyt ogólnym terminem, dlatego ludzie uważają go za mylący. W wyniku wielu dyskusji z różnymi zwolennikami IoC zdecydowaliśmy się na nazwę Dependency Injection.

Mówiąc trochę: Inwersja kontroli oznacza wszystko, co odwraca strukturę kontroli programu od klasycznego projektu proceduralnego.

W dawnych czasach kluczowym przykładem tego było umożliwienie frameworkowi obsługi komunikacji między interfejsem użytkownika a kodem, zamiast pozostawiania kodu do generowania interfejsu bezpośrednio.

W późniejszych czasach (kiedy takie struktury były w większości zdominowane, więc pytanie nie było już istotne), przykładem było odwrócenie kontroli nad instancjami obiektów.

Fowler i inni postanowili, że termin Inwersja kontroli obejmuje zbyt wiele technik i potrzebowaliśmy nowego terminu na konkretny przykład tworzenia instancji obiektów (wstrzykiwanie zależności), ale do czasu zawarcia umowy wyrażenie „kontener IoC” „wystartował.

Powoduje to znaczne zamulenie wody, ponieważ pojemnik IoC jest specyficznym rodzajem wstrzykiwania zależności, ale wstrzykiwanie zależności jest szczególnym rodzajem odwrócenia kontroli. Właśnie dlatego otrzymujesz takie niejasne odpowiedzi, bez względu na to, gdzie spojrzysz.

pdr
źródło
4
Zwykle nie głosuję za bardzo, ale to świetna odpowiedź. 1 głos nie wystarczy. :(
RJD22,
1
ta odpowiedź naprawdę odpowiada na wszystkie pytania dotyczące zamieszania IoC i DI.
Ali Umair,
32

Oto zwykle stosowane „zwykłe” programy kontroli przepływu:

  • Uruchamiaj polecenia sekwencyjnie
  • Utrzymujesz kontrolę nad przepływem kontrolnym programu

Inwersja kontroli „odwraca” kontrolę nad przepływem, co oznacza, że ​​przewraca ją na głowę:

  • Twój program nie kontroluje już przepływu. Zamiast wywoływać polecenia według własnego uznania, musisz poczekać, aż zadzwoni ktoś inny .

Ta ostatnia linia jest ważna. Zamiast dzwonić do kogoś innego, kiedy masz na to ochotę, ktoś dzwoni do ciebie, kiedy ma na to ochotę.

Typowym tego przykładem są frameworki internetowe, takie jak Rails. Definiujesz kontrolery, ale tak naprawdę nie decydujesz, kiedy zostaną one wywołane. Rails dzwoni do nich, gdy uzna, że ​​jest taka potrzeba.

dsw88
źródło
19
[wstaw tutaj obowiązkowy żart „po sowiecku”]
Robert Harvey
2
Żartując, myślę, że to, co opisujesz, bardziej przypomina przekazywanie wiadomości, które od dziesięcioleci jest podstawowym elementem OO.
Robert Harvey
3
@ JimmyHoffa - To wcale nie jest źle - patrz tutaj . Odwrócenie kontroli jest bardziej ogólną koncepcją niż tworzenie zależności, a wstrzykiwanie zależności jest tylko jedną z form IoC.
Lee
7
@JimmyHoffa: Nie zgadzam się. Jest to tak samo poprawna definicja Inwersji Kontroli, jak twoja odpowiedź lub Robert, co jest dokładnie zamieszaniem, które Fowler opisuje przy tworzeniu frazy Dependency Injection (którą oboje nazywacie IoC).
pdr
5
Zgadzam się z tym stwierdzeniem @pdr: „Inwersja kontroli oznacza wszystko, co odwraca strukturę kontroli programu od klasycznego projektu proceduralnego”. To właśnie opisuję i to jest ogólne odwrócenie kontroli. Wstrzykiwanie zależności jest rodzajem IoC, ale nie jest to jedyna rzecz, która ćwiczy IoC
dsw88
13

Chodzi o to, kto kontroluje tworzenie instancji zależności.

Tradycyjnie, gdy klasa / metoda musi użyć innej klasy (zależność), jest ona tworzona bezpośrednio przez klasę / metodę. Kontroluje jego zależności.

W przypadku Inversion of Control (IoC) osoba dzwoniąca przeszła w zależności, dlatego tworzy ona zależność. Dzwoniący kontroluje zależności.

Kontrola miejsca tworzenia instancji zależności została odwrócona - zamiast znajdować się na „dole”, gdzie jest potrzebny kod, jest on tworzony na „górze”, gdzie wywoływany jest kod, który tego potrzebuje.

Oded
źródło
1
Nie zwykły angielski. Zawieść.
Robert Harvey
2
@RobertHarvey - jak gładka jest prosta?
Oded
4
@RobertHarvey Huh? Wydaje mi się to dość jasne ... Co nie jest jasne? Słowo „instancja” czy „zależności”?
Jimmy Hoffa
@JimmyHoffa: Zobacz moją odpowiedź, która stanowi konkretny przykład. IoC jest jednym z tych kłopotliwych terminów, których wszyscy używają, ale nikt ich nie wyjaśnia; ludzie używają kontenerów IoC w programach, które ich nie wymagają, ponieważ źle rozumieją. To powiedziawszy, myślę, że ta odpowiedź zawierała kilka edycji ninja. :)
Robert Harvey
To i post be @ dsw88 powyżej są dla mnie całkiem jasne. Słuchaj, gdybym nigdy nie słyszał o IoC, intuicyjnie pomyślałbym: „Och, kto może kontrolować coś, co przewraca się z jednej strony na drugą”. Dobra robota!
Oliver Williams,
2

Zazwyczaj wywołania kodu wyższego poziomu (tj. Kontrolują) kod niższego poziomu. Funkcja main () wywołuje funkcję (), funkcja () wywołuje bibliotekęFunkcja ().

Można to odwrócić, więc funkcja biblioteki niskiego poziomu na dole wywołuje funkcje wyższego poziomu.

Dlaczego chcesz to zrobić? Middleware. Czasami chcesz kontrolować najwyższy i najniższy poziom, ale na środku jest dużo pracy, której po prostu nie chcesz wykonywać. Weź implementację quicksort w C stdlib . Nazywasz się Quicksort na najwyższym poziomie. Qsort () podajesz wskaźnikowi funkcji do własnej funkcji, która implementuje komparator na cokolwiek chcesz. Po wywołaniu qsort () wywołuje tę funkcję komparatora. qsort () kontroluje / dzwoni / steruje funkcją wysokiego poziomu.

Philip
źródło
1

Oto prosty przegląd:

  1. Kontrola odnosi się do tego, co program robi dalej
  2. Na najwyższym poziomie są zwykle dwie rzeczy, które kontrolują kontrolę: sama aplikacja i użytkownik

W dawnych czasach kontrola była w pierwszej kolejności własnością aplikacji, a następnie użytkownika. Jeśli aplikacja potrzebuje czegoś od użytkownika, zatrzyma się i zapyta, a następnie przejdzie do następnego zadania. Interakcja użytkownika dostarczyła głównie danych, a nie kontrolowała, co zrobiła aplikacja. Jest to dla nas trochę obce, ponieważ często nie widzimy tego typu zachowań.

Jeśli zmienimy to i damy użytkownikowi podstawową kontrolę, wówczas odwrócimy kontrolę. Oznacza to, że zamiast użytkownik czeka na aplikację, aby dać jej coś do zrobienia, aplikacja siedzi i czeka, aż użytkownik da mu coś do zrobienia. GUI są świetnym przykładem tego i prawie wszystko, co ma pętla zdarzeń, ma odwróconą kontrolę.

Zauważ, że mój przykład jest na najwyższym poziomie i że tę koncepcję inwersji kontroli można wyodrębnić na różne warstwy kontroli w aplikacji (tj. Wstrzykiwanie zależności). Być może dlatego tak trudno jest uzyskać jednoznaczną odpowiedź.

Loren
źródło
0

Spróbujmy to zrozumieć na podstawie dwóch przykładów.

Przykład 1

We wcześniejszych czasach aplikacje generowały monity poleceń, aby akceptować dane wejściowe użytkownika jeden po drugim. Obecnie frameworki interfejsu użytkownika tworzą różne elementy interfejsu użytkownika, przechodzą przez różne zdarzenia tych elementów interfejsu użytkownika (takie jak najechanie myszą, kliknięcie itp.), A programy użytkownika / główne zapewniają przechwytywanie (na przykład detektory zdarzeń interfejsu użytkownika w Javie) do nasłuchiwania tych zdarzeń. Zatem „sterowanie” przepływem głównego elementu interfejsu użytkownika zostało przeniesione z programu użytkownika do środowiska interfejsu użytkownika. Wcześniej było w programie użytkownika.

Przykład 2

Rozważ klasę CustomerProcessorponiżej:

class CustomerProcessor
{
    SqlCustRepo custRepo = new SqlCustRepo(); 
    private void processCustomers()
    {
            Customers[] custs = custRepo.getAllCusts();
    }
}

Jeśli chcę processCustomer()być niezależny od jakiejkolwiek implementacji getAllCusts(), nie tylko tej dostarczonej przez SqlCustRepo, będę musiał pozbyć się linii: SqlCustRepo custRepo = new SqlCustRepo()i zastąpić ją czymś bardziej ogólnym, zdolnym do zaakceptowania różnego rodzaju implementacji, tak aby po processCustomers()prostu działała dla wszelkie zapewnione wdrożenie. Powyższy kod (tworzenie instancji wymaganej klasy SqlCustRepowedług logiki programu głównego) jest tradycyjnym sposobem i nie osiąga celu oddzielenia processCustomers()od implementacji getAllCusts(). Podczas odwracania kontroli kontener tworzy instancję wymaganej klasy implementacji (określonej przez, powiedzmy konfigurację xml), wstrzykuje ją do logiki programu głównego, która zostaje powiązana według określonych haków (powiedzmy przez @Autowiredadnotację lub getBean()metodę w ramach Spring).

Zobaczmy, jak to zrobić. Rozważ poniższy kod.

Config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="custRepo" class="JsonCustRepo" />
</beans>

CustRepo.java

interface ICustRepo 
{ ... }

JsonCustRepo.java

class JsonCustRepo implements CustRepo
{ ... }

App.java

class App
{
    public static void main(String[] args) 
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
        ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
    }
}

Możemy też mieć

class GraphCustRepo implements ICustRepo { ... }   

i

<bean id="custRepo" class="GraphCustRepo">

i nie będziemy musieli zmieniać App.java.

Nad kontenerem (który jest strukturą sprężystą) odpowiada za skanowanie pliku xml, tworzenie instancji fasoli określonego typu i wstrzykiwanie jej do programu użytkownika. Program użytkownika nie ma kontroli nad tym, która klasa jest tworzona.

PS: IoC to ogólna koncepcja, którą można osiągnąć na wiele sposobów. Powyższe przykłady osiągają to poprzez wstrzyknięcie zależności.

Odniesienie: artykuł Martina Fowlera .

Mahesha999
źródło