Inwersja kontroli (IoC) może być dość myląca, gdy zostanie po raz pierwszy napotkana.
- Co to jest?
- Który problem rozwiązuje?
- Kiedy należy używać, a kiedy nie?
Inwersja kontroli (IoC) może być dość myląca, gdy zostanie po raz pierwszy napotkana.
Odpowiedzi:
Wzorce Inversion of Control (IoC) i Dependency Injection (DI) polegają na usuwaniu zależności z kodu.
Załóżmy na przykład, że Twoja aplikacja ma edytor tekstu i chcesz sprawdzić pisownię. Twój standardowy kod wyglądałby mniej więcej tak:
public class TextEditor {
private SpellChecker checker;
public TextEditor() {
this.checker = new SpellChecker();
}
}
To, co tutaj zrobiliśmy, tworzy zależność między TextEditor
i SpellChecker
. W scenariuszu IoC zamiast tego zrobilibyśmy coś takiego:
public class TextEditor {
private IocSpellChecker checker;
public TextEditor(IocSpellChecker checker) {
this.checker = checker;
}
}
W pierwszym przykładzie kodu tworzymy instancję SpellChecker
( this.checker = new SpellChecker();
), co oznacza, że TextEditor
klasa zależy bezpośrednio od SpellChecker
klasy.
W drugim przykładzie kodu tworzymy abstrakcję, mając SpellChecker
klasę zależności w TextEditor
sygnaturze konstruktora (nie inicjując zależności w klasie). Dzięki temu możemy wywołać zależność, a następnie przekazać ją do klasy TextEditor w następujący sposób:
SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);
Teraz klient tworzący TextEditor
klasę ma kontrolę nad tym, której SpellChecker
implementacji użyć, ponieważ wprowadzamy zależność do TextEditor
podpisu.
Odwrócenie kontroli jest tym, co dostajesz, gdy Twój program wywołuje zwrotne, np. Jak program GUI.
Na przykład w menu starej szkoły możesz mieć:
print "enter your name"
read name
print "enter your address"
read address
etc...
store in database
kontrolując w ten sposób przepływ interakcji użytkownika.
W programie GUI lub jakimś innym, zamiast tego mówimy:
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
Teraz kontrola jest odwrócona ... zamiast komputera akceptującego dane wejściowe użytkownika w ustalonej kolejności, użytkownik kontroluje kolejność wprowadzania danych i zapisywania danych w bazie danych.
Zasadniczo wszystko , co zawiera pętlę zdarzeń, wywołania zwrotne lub wyzwalacze, należy do tej kategorii.
Co to jest odwrócenie kontroli?
Jeśli wykonasz te dwa proste kroki, dokonałeś odwrócenia kontroli:
Istnieje kilka technik dla każdego z tych kroków w zależności od technologii / języka używanego do wdrożenia.
-
Część inwersji Inversion of Control (IoC) jest myląca; ponieważ inwersja jest terminem względnym. Najlepszym sposobem na zrozumienie IoC jest zapomnienie o tym słowie!
-
Przykłady
what-to-do
iwhen-to-do
Inwersja kontroli polega na oddzieleniu problemów.
Bez IoC : masz laptopa i przypadkowo zepsułeś ekran. Cholera, okazuje się, że ten sam model ekranu laptopa nie ma nigdzie na rynku. Więc utknąłeś.
Z IoC : masz komputer stacjonarny i przypadkowo zepsułeś ekran. Zauważysz, że możesz po prostu pobrać prawie każdy monitor stacjonarny z rynku i działa dobrze z twoim komputerem stacjonarnym.
W tym przypadku komputer pomyślnie wdraża IoC. Akceptuje różne typy monitorów, podczas gdy laptop nie, potrzebuje określonego ekranu, aby się naprawić.
Inversion of Control ((IoC)) polega na uzyskaniu wolności (bierzesz ślub, straciłeś wolność i jesteś kontrolowany. Rozwiedliście się, właśnie wdrożyliście Inversion of Control. To właśnie nazwaliśmy „oddzielonym”. Dobry system komputerowy zniechęca do bardzo bliskich relacji.) większa elastyczność (kuchnia w biurze serwuje tylko czystą wodę z kranu, co jest twoim jedynym wyborem, gdy chcesz się napić. Twój szef wdrożył Inversion of Control, konfigurując nowy ekspres do kawy. Teraz otrzymujesz elastyczność wyboru wody z kranu lub kawy) i mniejsza zależność (Twój partner ma pracę, nie masz pracy, jesteś zależny finansowo od partnera, więc jesteś pod kontrolą. Znajdujesz pracę, wdrożyłeś Inwersję Kontroli. Dobry system komputerowy zachęca do zależności.)
Kiedy korzystasz z komputera stacjonarnego, jesteś slave (lub powiedzmy, kontrolujesz). Musisz usiąść przed ekranem i spojrzeć na niego. Używanie klawiatury do pisania i nawigacja za pomocą myszy. Źle napisane oprogramowanie może cię jeszcze bardziej zniewolić. Jeśli zastąpisz komputer stacjonarny laptopem, masz nieco odwróconą kontrolę. Możesz go łatwo zabrać i poruszać się. Teraz możesz kontrolować swoje położenie za pomocą komputera, zamiast sterować nim.
Dzięki wdrożeniu Inversion of Control konsument oprogramowania / obiektu uzyskuje większą kontrolę / opcje nad oprogramowaniem / obiektami, zamiast być kontrolowanym lub mając mniej opcji.
Mając na uwadze powyższe pomysły. Nadal brakuje nam kluczowej części IoC. W scenariuszu IoC konsument oprogramowania / obiektu stanowi wyrafinowane środowisko. Oznacza to, że utworzony kod nie jest wywoływany przez Ciebie. Wyjaśnijmy teraz, dlaczego ten sposób działa lepiej dla aplikacji internetowej.
Załóżmy, że Twój kod to grupa pracowników. Muszą zbudować samochód. Pracownicy ci potrzebują miejsca i narzędzi (ramy oprogramowania) do budowy samochodu. Tradycyjne ramy oprogramowanie będzie jak garaż z wielu narzędzi. Dlatego pracownicy muszą sami opracować plan i użyć narzędzi do budowy samochodu. Budowa samochodu nie jest łatwym przedsięwzięciem, pracownikom naprawdę ciężko będzie odpowiednio zaplanować i współpracować. nowoczesnyramy oprogramowania będą przypominały nowoczesną fabrykę samochodów ze wszystkimi udogodnieniami i menedżerami. Pracownicy nie muszą tworzyć żadnego planu, menedżerowie (część frameworka, są najmądrzejszymi ludźmi i stworzyli najbardziej wyrafinowany plan) pomogą koordynować, aby pracownicy wiedzieli, kiedy wykonać swoją pracę (framework nazywa Twój kod). Pracownicy muszą być na tyle elastyczni, aby korzystać z narzędzi, które dają im menedżerowie (za pomocą wstrzykiwania zależności).
Chociaż pracownicy przekazują kontrolę nad zarządzaniem projektem na najwyższym poziomie menedżerom (struktura). Ale dobrze jest, aby niektórzy profesjonaliści ci pomogli. Z tego właśnie pochodzi koncepcja Internetu Rzeczy.
Nowoczesne aplikacje internetowe z architekturą MVC zależą od frameworka, który wykonuje routing URL i umieszcza Kontrolery na miejscu, aby framewor mógł zadzwonić.
Wstrzykiwanie zależności i odwracanie kontroli są powiązane. Wstrzykiwanie zależności odbywa się na poziomie mikro , a odwrócenie kontroli na poziomie makro . Musisz zjeść każdy kęs (implement DI), aby zakończyć posiłek (implement IoC).
Przed użyciem Inversion of Control powinieneś być świadomy faktu, że ma to swoje zalety i wady i powinieneś wiedzieć, dlaczego go używasz, jeśli to robisz.
Plusy:
Cons:
Osobiście widzę mocne strony IoC i bardzo mi się podobają, ale staram się unikać IoC, gdy tylko jest to możliwe, ponieważ zamienia twoje oprogramowanie w zbiór klas, które nie stanowią już „prawdziwego” programu, ale po prostu coś, co musi połączyć Konfiguracja XML lub metadane adnotacji i rozpadałyby się (i rozpadały) bez niego.
Artykuł w Wikipedii . Dla mnie odwrócenie kontroli zamienia Twój sekwencyjnie napisany kod i przekształca go w strukturę delegacji. Zamiast programu, który wyraźnie kontroluje wszystko, program tworzy klasę lub bibliotekę z pewnymi funkcjami, które mają być wywoływane, gdy pewne rzeczy się zdarzają.
Rozwiązuje duplikację kodu. Na przykład w dawnych czasach ręcznie pisałeś własną pętlę zdarzeń, odpytując biblioteki systemowe pod kątem nowych zdarzeń. W dzisiejszych czasach większość współczesnych interfejsów API po prostu informuje biblioteki systemowe, jakie zdarzenia są zainteresowane, i informuje o tym, kiedy się one zdarzają.
Odwrócenie kontroli jest praktycznym sposobem na ograniczenie duplikacji kodu, a jeśli odkryjesz, że kopiujesz całą metodę i zmieniasz tylko niewielką część kodu, możesz rozważyć rozwiązanie problemu z odwróceniem kontroli. Odwrócenie kontroli jest łatwe w wielu językach dzięki koncepcji delegatów, interfejsów, a nawet surowych wskaźników funkcji.
Nie jest właściwe stosowanie we wszystkich przypadkach, ponieważ przepływ programu może być trudniejszy do śledzenia, gdy jest napisany w ten sposób. Jest to przydatny sposób projektowania metod podczas pisania biblioteki, która będzie ponownie używana, ale powinna być używana oszczędnie w rdzeniu własnego programu, chyba że naprawdę rozwiązuje problem duplikacji kodu.
Ale myślę, że musisz być bardzo ostrożny. Jeśli nadużyjesz tego wzorca, stworzysz bardzo skomplikowany projekt i jeszcze bardziej skomplikowany kod.
Jak w tym przykładzie z TextEditor: jeśli masz tylko jeden moduł sprawdzania pisowni, może nie jest tak naprawdę konieczne korzystanie z IoC? Chyba że musisz pisać testy jednostkowe lub coś ...
W każdym razie: bądź rozsądny. Wzory projektowe to dobre praktyki, ale nie należy ich głosić w Biblii. Nie przyklejaj go wszędzie.
IoC / DI dla mnie wypiera zależności do obiektów wywołujących. Super proste.
Nietechniczną odpowiedzią jest możliwość wymiany silnika w samochodzie tuż przed jego włączeniem. Jeśli wszystko się połączy (interfejs), jesteś dobry.
Załóżmy, że jesteś przedmiotem. Idziesz do restauracji:
Bez IoC : prosisz o „jabłko” i zawsze podajesz jabłko, gdy prosisz o więcej.
Z IoC : możesz poprosić o „owoce”. Możesz otrzymać różne owoce za każdym razem, gdy je serwujesz. na przykład jabłko, pomarańcza lub arbuz.
Oczywiście IoC jest preferowane, gdy lubisz odmiany.
Odwrócenie kontroli jest wzorcem stosowanym do odsprzęgania komponentów i warstw w systemie. Wzorzec jest implementowany poprzez wstrzykiwanie zależności do komponentu podczas jego konstruowania. Zależności te są zwykle dostarczane jako interfejsy do dalszego oddzielania i wspierania testowalności. Kontenery IoC / DI, takie jak Castle Windsor, Unity są narzędziami (bibliotekami), których można używać do zapewniania IoC. Narzędzia te zapewniają rozszerzone funkcje wykraczające poza proste zarządzanie zależnościami, w tym okres istnienia, AOP / przechwytywanie, zasady itp.
za. Zwalnia komponent z odpowiedzialności za zarządzanie jego zależnościami.
b. Zapewnia możliwość zamiany implementacji zależności w różnych środowiskach.
do. Umożliwia testowanie komponentu poprzez wyśmiewanie zależności.
re. Zapewnia mechanizm udostępniania zasobów w całej aplikacji.
za. Krytyczne przy tworzeniu testów opartych na testach. Bez IoC testowanie może być trudne, ponieważ testowane komponenty są silnie sprzężone z resztą systemu.
b. Krytyczny przy opracowywaniu systemów modułowych. System modułowy to system, którego elementy można wymienić bez konieczności ponownej kompilacji.
do. Krytyczne, jeśli istnieje wiele przekrojowych problemów, które należy rozwiązać, zwłaszcza w aplikacji korporacyjnej.
Odpowiadając tylko na pierwszą część. Co to jest?
Inwersja kontroli (IoC) oznacza tworzenie instancji zależności najpierw i drugiej instancji klasy (opcjonalnie wstrzykiwanie ich przez konstruktor), zamiast tworzenia instancji klasy najpierw, a następnie instancji klasy tworzącej instancje zależności. Tak więc odwrócenie sterowania odwraca się przepływ sterowania programem. Zamiast z odbierającym kontrolującego ten przepływ sterowania (podczas tworzenia zależnościami), przy czym rozmówca kontroluje przepływ kontroli programu .
Spiszę moje proste zrozumienie tych dwóch terminów:
For quick understanding just read examples*
Wstrzykiwanie zależności (DI):
Wstrzykiwanie zależności zwykle oznacza przekazanie obiektu, od którego zależy metoda, jako parametru do metody, zamiast tworzenia metody zależnej przez metodę .
W praktyce oznacza to, że metoda nie zależy bezpośrednio od konkretnego wdrożenia; każda implementacja spełniająca wymagania może zostać przekazana jako parametr.
Dzięki tym obiektom powiedz im o swoich zależnościach. A wiosna czyni go dostępnym.
Prowadzi to do luźno powiązanego tworzenia aplikacji.
Quick Example:EMPLOYEE OBJECT WHEN CREATED,
IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
(if address is defines as dependency by Employee object)
Kontener Inversion of Control (IoC):
jest to wspólna cecha frameworków, MKOl zarządza obiektami Java
- od instancji do zniszczenia poprzez BeanFactory.
Komponenty Java, które są tworzone przez kontener IoC, nazywane są fasolami, a kontener IoC zarządza zakresem komponentu bean, zdarzeniami cyklu życia oraz wszelkimi funkcjami AOP, dla których został skonfigurowany i zakodowany.
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
.
Implementując Inversion of Control, użytkownik oprogramowania / obiektu uzyskuje więcej kontroli / opcji nad oprogramowaniem / obiektami, zamiast być kontrolowanym lub mając mniej opcji.
Odwrócenie kontroli jako wytyczne projektowe służy następującym celom:
Występuje oddzielenie wykonania określonego zadania od realizacji.
Każdy moduł może skupić się na tym, do czego jest przeznaczony.
Moduły nie przyjmują żadnych założeń dotyczących tego, co robią inne systemy, ale polegają na swoich umowach.
Zastąpienie modułów nie ma wpływu ubocznego na inne moduły.
Będę tutaj utrzymywał abstrakcję. Możesz odwiedzić poniższe linki, aby uzyskać szczegółowe informacje na ten temat.
Dobra lektura z przykładem
Zgadzam się z NilObject , ale chciałbym dodać do tego:
jeśli okaże się, że kopiujesz całą metodę i zmieniasz tylko niewielki fragment kodu, możesz rozważyć zajęcie się tym z odwróceniem kontroli
Jeśli kopiujesz i wklejasz kod, prawie zawsze robisz coś złego. Skodyfikowane jako zasada projektowania Raz i tylko raz .
Na przykład zadaniem nr 1 jest utworzenie obiektu. Bez koncepcji IOC zadanie nr 1 powinno być wykonane przez programistę, ale w przypadku koncepcji IOC zadanie nr 1 byłoby wykonane przez kontener.
W skrócie Kontrola zostaje odwrócona z Programmera do kontenera. Nazywa się to więc odwróceniem kontroli.
Znalazłem jeden dobry przykład tutaj .
Powiedzmy, że umawiamy się na spotkanie w jakimś hotelu.
Wiele osób, wiele karafek wody, wiele plastikowych kubków.
Kiedy ktoś chce się napić, napełnia kubek, pije i rzuca kubek na podłogę.
Po godzinie czy coś mamy podłogę pokrytą plastikowymi kubkami i wodą.
Pozwól odwrócić kontrolę.
To samo spotkanie w tym samym miejscu, ale zamiast plastikowych kubków mamy kelnera z jednym szklanym kubkiem (Singleton)
i ona cały czas oferuje gościom picie.
Kiedy ktoś chce się napić, wychodzi ze szklanki kelnera, pije i oddaje kelnerowi.
Pomijając kwestię higienicznej, ostatniej formy kontroli procesu picia, jest on znacznie bardziej skuteczny i ekonomiczny.
I dokładnie to robi Spring (inny kontener IoC, na przykład: Guice). Zamiast zezwalać aplikacji na tworzenie potrzebnych informacji za pomocą nowego słowa kluczowego (biorąc plastikowy kubek), pojemnik Spring IoC cały czas oferuje stosowanie tego samego wystąpienia (singletonu) potrzebnego obiektu (szklanka wody).
Pomyśl o sobie jako o organizatorze takiego spotkania. Potrzebujesz sposobu na przesłanie tego do administracji hotelu
członkowie spotkania będą potrzebować szklanki wody, ale nie bułki z masłem.
Przykład:-
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
}
Przydatne linki:-
Wydaje się, że najbardziej mylącą rzeczą w „IoC” akronimie i nazwie, dla której on oznacza, jest to, że nazwa jest zbyt czarująca - nazwa prawie szumowa.
Czy naprawdę potrzebujemy nazwy, za pomocą której można opisać różnicę między programowaniem proceduralnym a programowaniem zdarzeń? OK, jeśli musimy, ale czy musimy wybrać zupełnie nową nazwę „większe niż życie”, która dezorientuje bardziej niż rozwiązuje?
Odwrócenie kontroli ma miejsce, gdy idziesz do sklepu spożywczego, a twoja żona daje ci listę produktów do kupienia.
W zakresie programowania przekazała funkcję zwrotną getProductList()
do funkcji, którą wykonujesz - doShopping()
.
Pozwala użytkownikowi funkcji zdefiniować niektóre jego części, czyniąc ją bardziej elastyczną.
getProductList()
, musisz znaleźć źródło pieniędzy, co oznacza, że kontrola jest po twojej stronie. W przypadku inwersji będzie kontrolowała, co oznacza, że pieniądze, które zapewni ona na zakup.
Znalazłem tutaj bardzo jasny przykład , który wyjaśnia, w jaki sposób „sterowanie jest odwrócone”.
Kod klasyczny (bez wstrzykiwania zależności)
Oto, w jaki sposób kod nieobsługujący DI będzie działać z grubsza:
Za pomocą wstrzykiwania zależności
Oto jak z grubsza działa kod korzystający z DI:
Kontrola zależności jest odwrócona z jednej osoby wzywającej na drugą.
Jakie problemy rozwiązuje?
Wstrzykiwanie zależności ułatwia wymianę z różnymi implementacjami wstrzykiwanych klas. Podczas testowania jednostkowego można wstrzykiwać fałszywą implementację, co znacznie ułatwia testowanie.
Przykład: Załóżmy, że Twoja aplikacja przechowuje plik przesłany przez użytkownika na Dysku Google, z DI kod kontrolera może wyglądać następująco:
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) {}
}
Gdy zmienią się twoje wymagania, powiedz, zamiast GoogleDrive zostaniesz poproszony o użycie Dropbox. Musisz tylko napisać implementację Dropbox dla StorageServiceInterface. Nie wprowadzasz żadnych zmian w kontrolerze, dopóki implementacja Dropbox przestrzega interfejsu StorageServiceInterface.
Podczas testowania można utworzyć próbkę dla StorageServiceInterface za pomocą fikcyjnej implementacji, w której wszystkie metody zwracają wartość null (lub dowolną wstępnie zdefiniowaną wartość zgodnie z wymaganiami dotyczącymi testowania).
Zamiast tego, jeśli masz klasę kontrolera do zbudowania obiektu pamięci za pomocą new
słowa kluczowego w ten sposób:
class SomeController
{
private $storage;
function __construct()
{
$this->storage = new GoogleDriveService();
}
public function myFunction ()
{
return $this->storage->getFile($fileName);
}
}
Jeśli chcesz zmienić za pomocą implementacji Dropbox, musisz zastąpić wszystkie wiersze, w których new
budowany jest obiekt GoogleDriveService i użyć DropboxService. Poza tym podczas testowania klasy SomeController konstruktor zawsze oczekuje klasy GoogleDriveService i uruchamiane są rzeczywiste metody tej klasy.
Kiedy jest to właściwe, a kiedy nie? Moim zdaniem używasz DI, jeśli uważasz, że istnieją (lub mogą być) alternatywne implementacje klasy.
Bardzo proste pisemne wyjaśnienie można znaleźć tutaj
http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html
To mówi -
„Każda nietrywialna aplikacja składa się z dwóch lub więcej klas, które współpracują ze sobą w celu wykonania logiki biznesowej. Tradycyjnie każdy obiekt jest odpowiedzialny za uzyskanie własnych odniesień do obiektów, z którymi współpracuje (jego zależności). obiekty otrzymują swoje zależności w czasie tworzenia przez jakiś zewnętrzny byt, który koordynuje każdy obiekt w systemie. Innymi słowy, zależności są wstrzykiwane do obiektów. ”
Odwrócenie kontroli jest ogólną zasadą, podczas gdy funkcja Dependency Injection realizuje tę zasadę jako wzorzec projektowy do budowy grafów obiektowych (tj. Konfiguracja kontroluje, w jaki sposób obiekty się do siebie odnoszą, a nie sam obiekt kontroluje sposób uzyskania odniesienia do innego obiektu).
Patrząc na odwrócenie kontroli jako wzorzec projektowy, musimy spojrzeć na to, co odwracamy. Wstrzykiwanie zależności odwraca kontrolę nad konstruowaniem wykresu obiektów. Odwrócona kontrola, jeśli jest to powiedziane dla laika, oznacza zmianę przepływu kontroli w programie. Na przykład. W tradycyjnej samodzielnej aplikacji mamy główną metodę, z której kontrola jest przekazywana do innych bibliotek stron trzecich (w przypadku, gdy korzystaliśmy z funkcji biblioteki strony trzeciej), ale poprzez odwrócenie kontroli kontrola jest przenoszona z kodu biblioteki strony trzeciej do naszego kodu , ponieważ korzystamy z usług biblioteki zewnętrznej. Istnieją jednak inne aspekty, które należy odwrócić w programie - np. Wywołanie metod i wątków w celu wykonania kodu.
Dla zainteresowanych bardziej dogłębnie na temat Inwersji Kontroli opublikowano artykuł przedstawiający pełniejszy obraz Inwersji Kontroli jako wzorca projektowego (OfficeFloor: używanie wzorców biurowych do ulepszania projektowania oprogramowania http://doi.acm.org/10.1145/ 2739011.2739013 z bezpłatną kopią dostępną do pobrania ze strony http://www.officefloor.net/about.html ).
Zidentyfikowano następujący związek:
Odwrócenie kontroli (dla metod) = wtrysk zależny (stan) + wtrysk kontynuacyjny + wtrysk nici
Podsumowanie powyższej zależności dla Inversion of Control dostępne - http://dzone.com/articles/inversion-of-coupling-control
IoC polega na odwróceniu relacji między twoim kodem a kodem strony trzeciej (biblioteka / framework):
DI (Dependency Injection) dotyczy przepływu kontroli w aplikacji. Tradycyjna aplikacja komputerowa miała przepływ sterowania z aplikacji (metoda main ()) do innych wywołań metod bibliotecznych, ale w przypadku sterowania DI przepływ jest odwrócony, dzięki czemu framework zajmuje się uruchamianiem aplikacji, inicjowaniem jej i wywoływaniem metod w razie potrzeby.
W końcu zawsze wygrywasz :)
Podoba mi się to wyjaśnienie: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/
Zaczyna się prosty i pokazuje również przykłady kodu.
Konsument, X, potrzebuje konsumowanej klasy Y, aby coś osiągnąć. To wszystko jest dobre i naturalne, ale czy X naprawdę musi wiedzieć, że używa Y?
Czy nie wystarczy, że X wie, że używa czegoś, co ma zachowanie, metody, właściwości itp. Y, nie wiedząc, kto faktycznie wdraża to zachowanie?
Wyodrębniając abstrakcyjną definicję zachowania używanego przez X w Y, zilustrowaną jako I poniżej, i pozwalając konsumentowi X na użycie tego wystąpienia zamiast Y, może on nadal robić to, co robi, bez konieczności poznawania specyfiki Y.
Na powyższej ilustracji Y implementuje I, a X używa instancji I. Chociaż jest całkiem możliwe, że X nadal używa Y, interesujące jest to, że X o tym nie wie. Po prostu wie, że używa czegoś, co implementuje I.
Przeczytaj artykuł, aby uzyskać dodatkowe informacje i opis korzyści, takich jak:
...
Rozumiem, że odpowiedź została już tutaj podana. Ale nadal uważam, że niektóre podstawowe informacje o odwróceniu kontroli muszą być tutaj omówione szczegółowo dla przyszłych czytelników.
Inwersja kontroli (IoC) została zbudowana na bardzo prostej zasadzie zwanej Hollywood Principle . I mówi, że
Nie dzwoń do nas, my zadzwonimy do ciebie
Oznacza to, że nie idź do Hollywood, aby spełnić swoje marzenie, a jeśli jesteś godny, Hollywood cię odnajdzie i spełni twoje marzenie. Prawie odwrócony, co?
Teraz, gdy dyskutujemy o zasadzie IoC, zapominamy o Hollywood. Dla IoC musi być trzy element, Hollywood, ty i zadanie takie jak spełnienie twojego marzenia.
W naszym świecie programowania, Hollywood stanowią ogólne ramy (może być napisany przez ciebie lub kogoś innego), Państwo reprezentują kod użytkownika został zapisany i zadanie reprezentowania rzeczą, którą chcesz osiągnąć w kodzie. Teraz nigdy nie zaczynasz samodzielnie uruchamiać swojego zadania, nie w IoC! Zamiast tego zaprojektowałeś wszystko w taki sposób, że twoje środowisko uruchomi za ciebie zadanie. W ten sposób zbudowałeś platformę wielokrotnego użytku, która może uczynić kogoś bohaterem lub innym złoczyńcą. Ale ten szkielet jest zawsze odpowiedzialny, wie, kiedy kogoś wybrać, i że ktoś wie tylko, czym chce być.
Podano by tutaj prawdziwy przykład z życia. Załóżmy, że chcesz opracować aplikację internetową. Tak więc tworzysz strukturę, która będzie obsługiwać wszystkie typowe rzeczy, które aplikacja internetowa powinna obsługiwać, takie jak obsługa żądania http, tworzenie menu aplikacji, serwowanie stron, zarządzanie plikami cookie, wyzwalanie zdarzeń itp
A potem zostawiasz pewne haczyki w swoim frameworku, w których możesz umieścić kolejne kody w celu wygenerowania niestandardowego menu, stron, plików cookie lub rejestrowania niektórych zdarzeń użytkownika itp. Na każde żądanie przeglądarki, twoja struktura uruchomi się i wykona twoje niestandardowe kody, jeśli zostanie zaczepiona, a następnie odeśle ją do przeglądarki.
Pomysł jest więc bardzo prosty. Zamiast tworzyć aplikację użytkownika, która będzie kontrolować wszystko, najpierw stworzysz platformę wielokrotnego użytku, która będzie kontrolować wszystko, a następnie napiszesz niestandardowe kody i podpisz je do ramy, aby wykonać je na czas.
Laravel i EJB są przykładami takich ram.
Odniesienie:
Programowanie mówienia
IoC w prostych słowach: jest to użycie interfejsu jako sposobu na określone coś (takie pole lub parametr) jako symbol wieloznaczny, który może być używany przez niektóre klasy. Pozwala to na ponowne użycie kodu.
Załóżmy na przykład, że mamy dwie klasy: Pies i Kot . Oba mają te same cechy / stany: wiek, rozmiar, wagę. Zamiast tworzyć klasę usług o nazwie DogService i CatService , mogę utworzyć jedną o nazwie AnimalService, która pozwala korzystać z Dog i Cat tylko wtedy, gdy używają interfejsu IAnimal .
Jednak pragmatycznie rzecz biorąc, ma pewne zacofanie.
a) Większość programistów nie wie, jak z niego korzystać . Na przykład mogę utworzyć klasę o nazwie Klient i mogę automatycznie (za pomocą narzędzi IDE) utworzyć interfejs o nazwie ICustomer . Dlatego nierzadko znajduje się folder wypełniony klasami i interfejsami, bez względu na to, czy interfejsy zostaną ponownie użyte, czy nie. Nazywa się BLOATED. Niektórzy ludzie mogą argumentować, że „możemy być w przyszłości, moglibyśmy z niego skorzystać”. : - |
b) Ma pewne ograniczenia. Na przykład, porozmawiajmy o sprawie Dog and Cat i chcę dodać nową usługę (funkcjonalność) tylko dla psów. Powiedzmy, że chcę obliczyć liczbę dni, które muszę wyszkolić psa ( trainDays()
), ponieważ kot jest bezużyteczny, kotów nie można trenować (żartuję).
b.1) Jeśli dodam trainDays()
do usługi AnimalService Service, działa ona również z kotami i wcale nie jest ważna.
b.2) Mogę dodać warunek, w trainDays()
którym ocenia, która klasa jest używana. Ale całkowicie przełamie IoC.
b.3) Mogę stworzyć nową klasę usług o nazwie DogService tylko dla nowej funkcjonalności. Ale zwiększy to łatwość konserwacji kodu, ponieważ będziemy mieć dwie klasy usług (o podobnej funkcjonalności) dla Dog i jest źle.
Przeczytałem wiele odpowiedzi na ten temat, ale jeśli ktoś nadal jest zdezorientowany i potrzebuje dodatkowo ultra „laikańskiego terminu”, aby wyjaśnić IoC, oto moje zdanie:
Wyobraź sobie, że rodzic i dziecko rozmawiają ze sobą.
Bez IoC:
* Rodzic : Możesz mówić tylko wtedy, gdy zadam ci pytania, i możesz działać tylko wtedy, gdy udzielę ci pozwolenia.
Rodzic : Oznacza to, że nie możesz mnie zapytać, czy możesz jeść, bawić się, iść do łazienki, a nawet spać, jeśli cię nie zapytam.
Rodzic : Czy chcesz jeść?
Dziecko : Nie.
Rodzic : Dobra, wrócę. Zaczekaj na mnie.
Dziecko : (chce się bawić, ale ponieważ rodzic nie ma pytania, dziecko nie może nic zrobić).
Po upływie 1 godziny...
Rodzic : wróciłem. Chcesz zagrać?
Dziecko : Tak.
Rodzic : zezwolenie przyznane.
Dziecko : (w końcu jest w stanie grać).
Ten prosty scenariusz wyjaśnia, że sterowanie jest wyśrodkowane na obiekcie nadrzędnym. Wolność dziecka jest ograniczona i w dużej mierze zależy od pytania rodzica. Dziecko może mówić TYLKO, gdy zostanie o to poproszony, i może działać TYLKO , gdy uzyska zgodę.
Z IoC:
Dziecko ma teraz możliwość zadawania pytań, a rodzic może odpowiedzieć odpowiedziami i uprawnieniami. Oznacza to po prostu, że sterowanie jest odwrócone! Dziecko może teraz zadawać pytania w dowolnym momencie i chociaż nadal istnieje zależność od rodzica w zakresie uprawnień, nie jest on zależny od sposobu mówienia / zadawania pytań.
Z technologicznego punktu widzenia jest to bardzo podobne do interakcji między konsolą / powłoką / cmd a GUI. (Która jest odpowiedzią Marka Harrisona powyżej najwyższej odpowiedzi nr 2). W konsoli jesteś zależny od tego, o co Cię pyta / wyświetlasz i nie możesz przejść do innych menu i funkcji, nie odpowiadając najpierw na pytanie; po ścisłym sekwencyjnym przepływie. (programowo jest to jak pętla metody / funkcji). Jednak w przypadku GUI menu i funkcje są rozmieszczone, a użytkownik może wybrać wszystko, czego potrzebuje, dzięki czemu ma większą kontrolę i mniej ograniczeń. (programowo menu mają oddzwanianie po wybraniu i wykonywana jest akcja).
Odwrócenie kontroli polega na przekazaniu kontroli z biblioteki do klienta. Ma to większy sens, gdy mówimy o kliencie, który wstrzykuje (przekazuje) wartość funkcji (wyrażenie lambda) do funkcji wyższego rzędu (funkcja biblioteki), która kontroluje (zmienia) zachowanie funkcji biblioteki. Klient lub środowisko, które wstrzykuje zależności bibliotek (które przenoszą zachowanie) do bibliotek, może być również uważane za IoC
Ponieważ na pytanie jest już wiele odpowiedzi, ale żadna z nich nie pokazuje podziału terminu Inversion Control, widzę możliwość udzielenia bardziej zwięzłej i użytecznej odpowiedzi.
Inwersja kontroli to wzorzec, który implementuje zasadę inwersji zależności (DIP). DIP stwierdza, co następuje: 1. Moduły wysokiego poziomu nie powinny zależeć od modułów niskiego poziomu. Oba powinny zależeć od abstrakcji (np. Interfejsów). 2. Abstrakcje nie powinny zależeć od szczegółów. Szczegóły (konkretne wdrożenia) powinny zależeć od abstrakcji.
Istnieją trzy rodzaje odwrócenia kontroli:
Dostawcy odwracania interfejsu nie powinni definiować interfejsu. Zamiast tego konsument powinien zdefiniować interfejs, a dostawcy muszą go wdrożyć. Interfejs Inwersja pozwala wyeliminować konieczność modyfikacji konsumenta za każdym razem, gdy dodawany jest nowy dostawca.
Inwersja przepływu Zmienia kontrolę przepływu. Na przykład masz aplikację konsolową, w której prosiłeś o wprowadzenie wielu parametrów, a po każdym wprowadzonym parametrze musisz nacisnąć klawisz Enter. Możesz zastosować Flow Inversion i wdrożyć aplikację komputerową, w której użytkownik może wybrać sekwencję wprowadzania parametrów, użytkownik może edytować parametry, a na ostatnim etapie użytkownik musi nacisnąć klawisz Enter tylko raz.
Inwersja tworzenia Może być implementowana przez następujące wzorce: Wzorzec fabryczny, Lokalizator usług i Wstrzykiwanie zależności. Creation Inversion pomaga wyeliminować zależności między typami, przenosząc proces tworzenia obiektów zależności poza typ, który używa tych obiektów zależności. Dlaczego zależności są złe? Oto kilka przykładów: bezpośrednie utworzenie nowego obiektu w kodzie utrudnia testowanie; zmiana odnośników w złożeniach jest niemożliwa bez ponownej kompilacji (naruszenie zasady OCP); nie można łatwo zastąpić interfejsu użytkownika na pulpicie interfejsem użytkownika w sieci.
Więc numer 1 powyżej . Co to jest odwrócenie kontroli?
Utrzymanie jest dla mnie najważniejszą rzeczą. Gwarantuje to, że używam interfejsów, aby dwie klasy nie były ze sobą bliskie.
Korzystając z pojemnika takiego jak Castle Windsor, rozwiązuje on problemy konserwacyjne jeszcze lepiej. Możliwość zamiany komponentu, który trafia do bazy danych, na taki, który używa trwałości opartej na plikach bez zmiany linii kodu jest niesamowita (zmiana konfiguracji, gotowe).
A kiedy przejdziesz do generycznych, staje się jeszcze lepszy. Wyobraź sobie, że masz wydawcę wiadomości, który odbiera rekordy i publikuje wiadomości. Nie obchodzi go, co publikuje, ale potrzebuje mapera, aby przenieść coś z rekordu do wiadomości.
public class MessagePublisher<RECORD,MESSAGE>
{
public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
{
//setup
}
}
Napisałem go raz, ale teraz mogę wstrzyknąć wiele typów do tego zestawu kodu, jeśli opublikuję różne typy wiadomości. Potrafię także pisać programy mapujące, które pobierają zapis tego samego typu i mapują je na różne wiadomości. Używanie DI z Generics dało mi możliwość napisania bardzo mało kodu do wykonania wielu zadań.
O tak, istnieją obawy dotyczące testowalności, ale są one drugorzędne w stosunku do korzyści płynących z IoC / DI.
Zdecydowanie kocham IoC / DI.
3) Staje się bardziej odpowiednie w momencie, gdy masz średniej wielkości projekt o nieco większej złożoności. Powiedziałbym, że staje się to właściwe, gdy tylko zaczniesz odczuwać ból.
Tworzenie obiektu w klasie nazywa się ścisłym sprzężeniem, Spring usuwa tę zależność, postępując zgodnie z wzorcem projektowym (DI / IOC). W którym obiekcie klasy przekazywany jest konstruktor zamiast tworzenia w klasie. Ponadto podajemy zmienną referencyjną superklasy w konstruktorze, aby zdefiniować bardziej ogólną strukturę.