Was ist Umkehrung der Kontrolle?


1826

Die Inversion der Steuerung (IoC) kann beim ersten Auftreten ziemlich verwirrend sein.

  1. Was ist es?
  2. Welches Problem löst es?
  3. Wann ist es angebracht zu verwenden und wann nicht?

292
Das Problem bei den meisten dieser Antworten ist die verwendete Terminologie. Was ist ein Container? Inversion? Abhängigkeit? Erklären Sie es in Laienbegriffen ohne die großen Worte.
Kirk.burleson

13
Siehe auch auf Programmers.SE: Warum heißt Inversion of Control so?
Izkata

8
Es ist Dependency Injection (DI) - siehe Martin Fowlers Beschreibung hier: martinfowler.com/articles/injection.html#InversionOfControl
Ricardo Sanchez


Es ist ein Adjektiv, kein Substantiv, es ist keine Sache, es ist eine Beschreibung einer Änderung am Code, bei der die Steuerung des Flusses im Delegaten und nicht im Container liegt.
Martin Spamer

Antworten:


1523

Bei den Mustern Inversion of Control (IoC) und Dependency Injection (DI) geht es darum, Abhängigkeiten aus Ihrem Code zu entfernen.

Angenommen, Ihre Anwendung verfügt über eine Texteditor-Komponente und Sie möchten eine Rechtschreibprüfung durchführen. Ihr Standardcode würde ungefähr so ​​aussehen:

public class TextEditor {

    private SpellChecker checker;

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

Was wir hier getan haben, schafft eine Abhängigkeit zwischen dem TextEditorund dem SpellChecker. In einem IoC-Szenario würden wir stattdessen Folgendes tun:

public class TextEditor {

    private IocSpellChecker checker;

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

Im ersten Codebeispiel instanziieren wir SpellChecker( this.checker = new SpellChecker();), was bedeutet, dass die TextEditorKlasse direkt von der SpellCheckerKlasse abhängt .

Im zweiten Codebeispiel erstellen wir eine Abstraktion, indem wir die SpellCheckerAbhängigkeitsklasse in TextEditorder Konstruktorsignatur haben (die Abhängigkeit in der Klasse nicht initialisieren). Auf diese Weise können wir die Abhängigkeit aufrufen und dann wie folgt an die TextEditor-Klasse übergeben:

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

Jetzt hat der Client, der die TextEditorKlasse erstellt, die Kontrolle darüber, welche SpellCheckerImplementierung verwendet werden soll, da wir die Abhängigkeit in die TextEditorSignatur einfügen.


50
Gutes klares Beispiel. Angenommen, die ISpellChecker-Schnittstelle muss nicht an den Konstruktor des Objekts übergeben werden, sondern wird als einstellbare Eigenschaft (oder SetSpellChecker-Methode) verfügbar gemacht. Würde dies immer noch IoC darstellen?
devios1

25
chainguy1337 - ja das würde es. Die Verwendung solcher Setter wird als Setterinjektion bezeichnet, im Gegensatz zur Konstruktorinjektion (beide Techniken zur Abhängigkeitsinjektion). IoC ist ein ziemlich allgemeines Muster, aber die Abhängigkeitsinjektion erreicht IoC
Jack Ukleja

257
Trotz der vielen Stimmen ist diese Antwort falsch. Weitere Informationen finden Sie unter martinfowler.com/articles/injection.html#InversionOfControl . Beachten Sie insbesondere den Teil "Inversion of Control" ist ein zu allgemeiner Begriff, und daher finden ihn die Leute verwirrend. Infolgedessen haben wir uns bei vielen Diskussionen mit verschiedenen IoC-Befürwortern für den Namen "Dependency Injection" entschieden.
Rogério

45
Ich stimme @Rogeria zu. Das erklärt nicht, warum es IoC heißt und ich bin überrascht von der Anzahl der Stimmen ;-)
Aravind Yarram

31
Ich stehe auf der Seite von @Rogerio und @Pangaea. Dies mag ein gutes Beispiel für die Konstruktorinjektion sein, aber keine gute Antwort auf die ursprüngliche Frage. IoC, wie von Fowler definiert , kann ohne Verwendung einer Injektion jeglicher Art realisiert werden, z. B. durch Verwendung eines Service Locator oder sogar einer einfachen Vererbung.
Mtsz

642

Inversion of Control erhalten Sie, wenn Ihr Programm zurückruft, z. B. wie ein GUI-Programm.

In einem Menü der alten Schule könnten Sie beispielsweise Folgendes haben:

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

Dadurch wird der Fluss der Benutzerinteraktion gesteuert.

In einem GUI-Programm oder so sagen wir stattdessen:

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

Jetzt ist die Steuerung invertiert ... anstatt dass der Computer Benutzereingaben in einer festen Reihenfolge akzeptiert, steuert der Benutzer die Reihenfolge, in der die Daten eingegeben werden und wann die Daten in der Datenbank gespeichert werden.

Grundsätzlich fällt alles mit einer Ereignisschleife, Rückrufen oder Ausführungsauslösern in diese Kategorie.


161
Markiere diesen Kerl nicht. Technisch gesehen ist er korrekt. martinfowler.com/bliki/InversionOfControl.html IoC ist ein sehr allgemeines Prinzip . Der Kontrollfluss wird durch Abhängigkeitsinjektion "invertiert", da Sie Abhängigkeiten effektiv an ein externes System (z. B. IoC-Container) delegiert haben
Jack Ukleja

38
Stimmte Schneiders Kommentar zu. 5 Abstimmungen? Der Verstand verwirrt, da dies die einzige Antwort ist, die wirklich richtig ist. Beachten Sie die Eröffnung: " Wie ein GUI-Programm." Die Abhängigkeitsinjektion ist nur die am häufigsten gesehene Realisierung von IoC.
Jeff Sternal

40
In der Tat ist dies eine der wenigen richtigen Antworten! Leute, bei IoC geht es nicht grundsätzlich um Abhängigkeiten. Ganz und gar nicht.
Rogério

13
+1 - Dies ist eine gute Beschreibung (mit Beispiel) der folgenden Aussage von Martin Fowler: "Frühe Benutzeroberflächen wurden vom Anwendungsprogramm gesteuert. Sie hätten eine Folge von Befehlen wie" Name eingeben "," Adresse eingeben "; Ihre Das Programm würde die Eingabeaufforderungen steuern und eine Antwort auf jede einzelne abrufen. Bei grafischen (oder sogar bildschirmbasierten) Benutzeroberflächen würde das UI-Framework diese Hauptschleife enthalten, und Ihr Programm stellte stattdessen Ereignishandler für die verschiedenen Felder auf dem Bildschirm bereit Das Programm wurde invertiert und von Ihnen in das Framework verschoben. "
Ashish Gupta

14
Ich verstehe jetzt, warum es manchmal scherzhaft als "Hollywood-Prinzip: Rufen Sie uns nicht an, wir rufen Sie an" bezeichnet wird
Alexander Suraphel

419

Was ist Umkehrung der Kontrolle?

Wenn Sie diese einfachen zwei Schritte ausführen, haben Sie die Kontrolle umgekehrt:

  1. Trennen Sie den zu erledigenden Teil von dem zu erledigenden Teil.
  2. Stellen Sie sicher , dass , wenn ein Teil weiß so wenig wie möglich über welchen Teil; und umgekehrt.

Für jeden dieser Schritte sind verschiedene Techniken möglich, basierend auf der Technologie / Sprache, die Sie für Ihre Implementierung verwenden.

- -

Der Inversionsteil der Inversion of Control (IoC) ist verwirrend. weil Inversion der relative Begriff ist. Der beste Weg, IoC zu verstehen, besteht darin, dieses Wort zu vergessen!

- -

Beispiele

  • Handhabung des Events. Ereignishandler (Teil "Aufgaben") - Auslösen von Ereignissen (Teil "Aufgaben")
  • Schnittstellen. Komponentenclient (Teil der Aufgabe) - Implementierung der Komponentenschnittstelle (Teil der Aufgabe)
  • xEinheitsvorrichtung. Setup und TearDown (Teil, was zu tun ist) - xUnit-Frameworks rufen am Anfang Setup und am Ende TearDown auf (Teil, an dem zu tun ist).
  • Entwurfsmuster der Vorlagenmethode. Template-Methode When-to-Do-Teil - Primitive Unterklassenimplementierung What-to-Do-Teil
  • DLL-Containermethoden in COM. DllMain, DllCanUnload usw. (Teil, was zu tun ist) - COM / OS (Teil, wann zu tun ist)

Wie Sie Schnittstellen sagen. Komponenten-Client (Wann-zu-tun-Teil) als "Wann" ist nicht sinnvoll, wenn wir Schnittstellen verwenden (Beispiel: Abhängigkeitsinjektion). Wir abstrahieren ihn einfach und geben dem Client Flexibilität beim Hinzufügen einer Implementierung, aber es gibt kein "Wann". dort beteiligt. Ich bin mit "wann" einverstanden, wenn Ereignisse der Ereignisbehandlung ausgelöst werden.
OldSchool

Mit 'Komponenten-Client' meinte ich den Benutzer / Client der Schnittstelle. Der Client weiß, wann der Teil "Was ist zu tun?" Auszulösen ist, ob die Funktionalität erweitert werden soll oder nicht.
Rpattabi

Schauen Sie sich diesen wunderbaren Artikel von Martin Fowler an. Er zeigt, wie Schnittstellen den grundlegenden Teil der Umkehrung der Kontrolle ausmachen
rpattabi

Zwei erste Sätze sind brillant. genial !! Perfekte Trennung nach Aufgaben und Aufgaben !! Ich weiß nicht, warum andere Antworten so viele positive Stimmen bekommen. Sie sprechen nur Codes ohne Verständnis.
Amir Ziarati

2
Ich mag die Erklärung what-to-doundwhen-to-do
KimchiMan

164

Bei der Inversion von Kontrollen geht es darum, Bedenken zu trennen.

Ohne IoC : Sie haben einen Laptop und brechen versehentlich den Bildschirm. Und verdammt, Sie finden, dass das gleiche Modell Laptop-Bildschirm nirgendwo auf dem Markt ist. Also steckst du fest.

Mit IoC : Sie haben einen Desktop- Computer und brechen versehentlich den Bildschirm. Sie können fast jeden Desktop-Monitor vom Markt nehmen und er funktioniert gut mit Ihrem Desktop.

Ihr Desktop implementiert IoC in diesem Fall erfolgreich. Es akzeptiert eine Vielzahl von Monitoren, während der Laptop dies nicht tut, benötigt er einen bestimmten Bildschirm, um repariert zu werden.


1
@ Luo Jiong Hui Schöne Erklärung.
Sachin

3
Die meisten Designmuster, wenn nicht alle, haben ihre Gegenstücke in unserem täglichen Leben, die wir so gut sehen und verstehen. Der effizienteste Weg, ein Entwurfsmuster zu verstehen, besteht darin, die Gegenstücke des täglichen Lebens zu kennen. Und ich glaube, es gibt viele.
Luo Jiong Hui

6
Falsche Antwort. Sie erklären die Abhängigkeitsinjektion und nicht IoC. Siehe
Rogérios

2
Genau. Dies ist DI, nicht IoC. Wird immer noch positiv bewertet, da es sich um einen einfachen Ansatz handelt, der jedoch dazu beiträgt, das Verständnis des Themas zu erweitern.
Mär

Es erklärt die Abhängigkeitsinjektion. Nicht Ioc. Aber nette und klare Erklärung.
Chamin Wickramarathna

120

Bei Inversion of Control (oder IoC) geht es darum , Freiheit zu erlangen (Sie heiraten, Sie haben die Freiheit verloren und Sie werden kontrolliert. Sie sind geschieden, Sie haben gerade Inversion of Control implementiert. Das haben wir "entkoppelt" genannt. Gutes Computersystem Entmutigt eine sehr enge Beziehung.) Mehr Flexibilität (Die Küche in Ihrem Büro serviert nur sauberes Leitungswasser, das ist Ihre einzige Wahl, wenn Sie trinken möchten. Ihr Chef hat Inversion of Control implementiert, indem er eine neue Kaffeemaschine eingerichtet hat. Jetzt erhalten Sie die Flexibilität bei der Auswahl von Leitungswasser oder Kaffee.) und weniger Abhängigkeit (Ihr Partner hat einen Job, Sie haben keinen Job, Sie sind finanziell von Ihrem Partner abhängig, sodass Sie kontrolliert werden. Sie finden einen Job, Sie haben Inversion of Control implementiert. Ein gutes Computersystem fördert die Abhängigkeit.)

Wenn Sie einen Desktop-Computer verwenden, haben Sie Slave (oder sagen, gesteuert). Sie müssen vor einem Bildschirm sitzen und ihn betrachten. Verwenden der Tastatur zum Tippen und Verwenden der Maus zum Navigieren. Und eine schlecht geschriebene Software kann Sie noch mehr sklaven. Wenn Sie Ihren Desktop durch einen Laptop ersetzen, haben Sie die Steuerung etwas umgekehrt. Sie können es leicht nehmen und sich bewegen. Jetzt können Sie steuern, wo Sie sich mit Ihrem Computer befinden, anstatt dass Ihr Computer ihn steuert.

Durch die Implementierung von Inversion of Control erhält ein Software- / Objektkonsument mehr Steuerelemente / Optionen für die Software / Objekte, anstatt gesteuert zu werden oder weniger Optionen zu haben.

Mit den oben genannten Ideen im Auge. Wir vermissen immer noch einen wichtigen Teil von IoC. Im Szenario von IoC ist der Software- / Objektkonsument ein ausgeklügeltes Framework. Das bedeutet, dass der von Ihnen erstellte Code nicht von Ihnen selbst aufgerufen wird. Lassen Sie uns nun erklären, warum dieser Weg für eine Webanwendung besser funktioniert.

Angenommen, Ihr Code ist eine Gruppe von Arbeitern. Sie müssen ein Auto bauen. Diese Arbeiter benötigen einen Ort und Werkzeuge (ein Software-Framework), um das Auto zu bauen. Ein traditionelles Software-Framework wird wie eine Garage mit vielen Tools sein. Die Arbeiter müssen also selbst einen Plan erstellen und die Werkzeuge verwenden, um das Auto zu bauen. Ein Auto zu bauen ist kein einfaches Geschäft, es wird für die Arbeiter wirklich schwierig sein, richtig zu planen und zusammenzuarbeiten. Ein modernerDas Software-Framework wird wie eine moderne Autofabrik mit allen vorhandenen Einrichtungen und Managern sein. Die Mitarbeiter müssen keinen Plan erstellen, die Manager (Teil des Frameworks, sie sind die klügsten Leute und haben den ausgefeiltesten Plan erstellt) helfen bei der Koordinierung, damit die Mitarbeiter wissen, wann sie ihre Arbeit erledigen müssen (Framework ruft Ihren Code auf). Die Mitarbeiter müssen nur flexibel genug sein, um alle Tools zu verwenden, die die Manager ihnen zur Verfügung stellen (mithilfe von Dependency Injection).

Obwohl die Mitarbeiter den Managern (dem Framework) die Kontrolle über die Verwaltung des Projekts auf oberster Ebene geben. Aber es ist gut, wenn einige Profis helfen. Dies ist das Konzept von IoC wirklich kommen.

Moderne Webanwendungen mit einer MVC-Architektur hängen vom Framework für das URL-Routing ab und richten Controller ein, damit das Framework aufgerufen werden kann.

Abhängigkeitsinjektion und Inversion der Kontrolle hängen zusammen. Die Abhängigkeitsinjektion befindet sich auf der Mikroebene und die Inversion der Steuerung auf der Makroebene . Sie müssen jeden Bissen essen (DI implementieren), um eine Mahlzeit zu beenden (IoC implementieren).


21
Ich habe für den Vergleich von DI mit Ehe und IoC mit Scheidung gestimmt.
Marek Bar

"Obwohl die Mitarbeiter den Managern (dem Framework) die Kontrolle über die Verwaltung des Projekts auf oberster Ebene geben. Es ist jedoch gut, wenn einige Fachleute helfen. Dies ist das Konzept von IoC, von dem sie wirklich stammen." - Erstens ist die Kontrolle mit dem Manager. Können Sie erklären, wie diese Steuerung invertiert wird? Mit Hilfe von Fachleuten (welche Art von Fachleuten)? Wie ?
Istiaque Ahmed

@Istiaque Ahmed, im Vergleich zu einer Garage, in der die Arbeiter die volle Kontrolle über alles haben, kontrollieren Manager in modernen Autofabriken die Produktion. Jetzt werden die Arbeiter kontrolliert, anstatt zu kontrollieren. Seien Sie sich bewusst, dass Manager in diesem Zusammenhang Teil der modernen Autofabrik sind und nicht Teil der Arbeiter. Profis sind die Manager, die professionell in der Planung und Herstellung von Autos sind.
Luo Jiong Hui

2
Nachricht an verheiratete Menschen: Lassen Sie sich jetzt nicht scheiden, Ihre Kinderklassen können auch IoC implementieren.
Julian

Ja, das ist nur meine Vision von der Ehe auch IoC
Balron

94

Bevor Sie Inversion of Control verwenden, sollten Sie sich der Tatsache bewusst sein, dass es Vor- und Nachteile hat, und Sie sollten wissen, warum Sie es verwenden, wenn Sie dies tun.

Vorteile:

  • Ihr Code wird entkoppelt, sodass Sie Implementierungen einer Schnittstelle problemlos mit alternativen Implementierungen austauschen können
  • Es ist ein starker Motivator für die Codierung gegen Schnittstellen anstelle von Implementierungen
  • Es ist sehr einfach, Komponententests für Ihren Code zu schreiben, da dies nur von den Objekten abhängt, die in den Konstruktoren / Setzern akzeptiert werden, und Sie können sie problemlos isoliert mit den richtigen Objekten initialisieren.

Nachteile:

  • IoC invertiert nicht nur den Kontrollfluss in Ihrem Programm, sondern trübt ihn auch erheblich. Dies bedeutet, dass Sie nicht mehr nur Ihren Code lesen und von einem Ort zum anderen springen können, da die Verbindungen, die normalerweise in Ihrem Code enthalten sind, nicht mehr im Code enthalten sind. Stattdessen werden diese Metadaten in XML-Konfigurationsdateien oder Anmerkungen und im Code Ihres IoC-Containers interpretiert.
  • Es tritt eine neue Klasse von Fehlern auf, bei denen Ihre XML-Konfiguration oder Ihre Anmerkungen falsch sind und Sie viel Zeit damit verbringen können, herauszufinden, warum Ihr IoC-Container unter bestimmten Bedingungen eine Nullreferenz in eines Ihrer Objekte einfügt.

Persönlich sehe ich die Stärken von IoC und ich mag sie wirklich, aber ich vermeide IoC, wann immer dies möglich ist, weil es Ihre Software in eine Sammlung von Klassen verwandelt, die kein "echtes" Programm mehr darstellen, sondern nur noch etwas, das zusammengestellt werden muss XML-Konfigurations- oder Annotationsmetadaten und würden ohne sie auseinanderfallen (und fallen).


3
Der erste Betrug ist falsch. Idealerweise sollte in Ihrem Code nur 1 IOC-Container verwendet werden, und das ist Ihre Hauptmethode. Alles andere sollte von dort
herabfließen

23
Ich denke, er meint damit, dass Sie nicht einfach lesen können: myService.DoSomething () und zur Definition von DoSomething gehen, da myService mit IoC nur eine Schnittstelle ist und die tatsächliche Implementierung Ihnen unbekannt ist, es sei denn, Sie schauen nach es in XML-Konfigurationsdateien oder der Hauptmethode, wo Ihr ioc eingerichtet wird.
Chrismay

7
Hier hilft Resharper - "Klicken Sie auf" Zur Implementierung gehen "für die Benutzeroberfläche. Das Vermeiden von IoC (oder genauer DI aus Ihrem Beispiel) bedeutet wahrscheinlich auch, dass Sie nicht richtig testen
IThasTheAnswer

10
Betreff: Es verwandelt Ihre Software in eine Sammlung von Klassen, die kein "echtes" Programm mehr darstellen, sondern nur noch durch XML-Konfigurations- oder Anmerkungsmetadaten zusammengestellt werden müssen und ohne sie auseinanderfallen (und auseinanderfallen) - ich denke das ist sehr irreführend. Das Gleiche gilt für jedes Programm, das auf einem Framework geschrieben ist. Der Unterschied zu einem guten IoC-Container besteht darin, dass Sie in der Lage sein sollten, wenn Ihr Programm gut entworfen und geschrieben ist, es mit minimalen Änderungen an Ihrem Code herauszunehmen und in ein anderes zu plumpsen oder IoC insgesamt wegzuwerfen und Ihre Objekte von Hand zu konstruieren .
Der Awnry Bär

7
Schön, eine echte Antwort wie diese zu sehen! Ich denke, es gibt viele erfahrene Programmierer, die mit objektorientiertem Design und TDD-Praktiken vertraut sind und bereits Schnittstellen, Fabrikmuster, ereignisgesteuerte Modelle und Verspottungen verwenden, wo dies sinnvoll ist, bevor dieses Schlagwort "IoC" erfunden wurde. Leider behaupten zu viele Entwickler / "Architekten" schlechte Praktiken, wenn Sie ihre bevorzugten Frameworks nicht verwenden. Ich bevorzuge ein besseres Design, die Verwendung integrierter Sprachkonzepte und -werkzeuge, um das gleiche Ziel mit einem Bruchteil der Komplexität zu erreichen, dh ohne die Implementierung zu "trüben", wie Sie sagen :-)
Tony Wall

68
  1. Wikipedia-Artikel . Für mich bedeutet die Umkehrung der Kontrolle, dass Ihr sequentiell geschriebener Code in eine Delegierungsstruktur umgewandelt wird. Anstatt dass Ihr Programm explizit alles steuert, richtet Ihr Programm eine Klasse oder Bibliothek mit bestimmten Funktionen ein, die aufgerufen werden, wenn bestimmte Dinge passieren.

  2. Es löst Codeduplizierungen. Früher haben Sie beispielsweise manuell eine eigene Ereignisschleife geschrieben und die Systembibliotheken nach neuen Ereignissen abgefragt. Heutzutage teilen Sie den meisten modernen APIs den Systembibliotheken einfach mit, an welchen Ereignissen Sie interessiert sind, und lassen Sie wissen, wann sie eintreten.

  3. Die Umkehrung der Kontrolle ist ein praktischer Weg, um die Duplizierung von Code zu reduzieren. Wenn Sie feststellen, dass Sie eine gesamte Methode kopieren und nur einen kleinen Teil des Codes ändern, können Sie dies mit einer Umkehrung der Kontrolle in Angriff nehmen. Die Umkehrung der Steuerung wird in vielen Sprachen durch das Konzept von Delegaten, Schnittstellen oder sogar Rohfunktionszeigern erleichtert.

    Es ist nicht in allen Fällen angemessen, es zu verwenden, da der Ablauf eines Programms schwieriger zu verfolgen sein kann, wenn es auf diese Weise geschrieben wird. Es ist eine nützliche Methode zum Entwerfen von Methoden beim Schreiben einer Bibliothek, die wiederverwendet wird. Sie sollte jedoch im Kern Ihres eigenen Programms sparsam verwendet werden, es sei denn, dies löst wirklich ein Problem bei der Codeduplizierung.


37
Ich finde diesen Wikipedia-Artikel sehr verwirrend und muss repariert werden. Schauen Sie sich die Diskussionsseite für ein Lachen an.
devios1

Das Schreiben einer eigenen Ereignisschleife kann immer noch eine Umkehrung der Steuerung darstellen, wenn diese Ereignisschleife den Platz eines Frameworks einnimmt und der Rest des Codes das IoC-Prinzip verwendet, das Sie gerade für Ihr eigenes Framework geschrieben haben. Dies ist eigentlich keine schlechte Sache, es erhöht die Lesbarkeit zum Preis von nur ein bisschen mehr Codierung (nicht, dass es auch immer angemessen ist).
Lijat

45

Aber ich denke, man muss sehr vorsichtig damit sein. Wenn Sie dieses Muster überbeanspruchen, erstellen Sie ein sehr kompliziertes Design und noch komplizierteren Code.

Wie in diesem Beispiel mit TextEditor: Wenn Sie nur einen SpellChecker haben, ist es möglicherweise nicht wirklich notwendig, IoC zu verwenden? Es sei denn, Sie müssen Unit-Tests schreiben oder so ...

Wie auch immer: sei vernünftig. Designmuster sind gute Praktiken, aber keine zu predigende Bibel. Kleben Sie es nicht überall hin.


3
Woher wissen Sie, dass Sie nur eine Rechtschreibprüfung haben?
Trace

@Trace Sie könnten wissen, wie das Programm, das Sie schreiben werden, zum Beispiel verwendet wird. Dennoch sind einige Techniken wie die Abhängigkeitsinjektion so billig, dass es selten einen Grund gibt, sie in einem solchen Fall nicht zu verwenden.
Lijat

44

IoC / DI drückt für mich Abhängigkeiten zu den aufrufenden Objekten aus. Super einfach.

Die nicht-technische Antwort ist, dass Sie einen Motor in einem Auto austauschen können, bevor Sie ihn einschalten. Wenn alles richtig läuft (die Schnittstelle), sind Sie gut.


44

Angenommen, Sie sind ein Objekt. Und du gehst in ein Restaurant:

Ohne IoC : Sie fragen nach "Apfel", und Ihnen wird immer Apfel serviert, wenn Sie mehr fragen.

Mit IoC : Sie können nach "Obst" fragen. Sie können jedes Mal, wenn Sie serviert werden, verschiedene Früchte bekommen. Zum Beispiel Apfel-, Orangen- oder Wassermelone.

Daher wird IoC natürlich bevorzugt, wenn Sie die Sorten mögen.


26
  1. Die Inversion der Steuerung ist ein Muster, das zum Entkoppeln von Komponenten und Schichten im System verwendet wird. Das Muster wird implementiert, indem Abhängigkeiten in eine Komponente eingefügt werden, wenn es erstellt wird. Diese Abhängigkeiten werden normalerweise als Schnittstellen zur weiteren Entkopplung und zur Unterstützung der Testbarkeit bereitgestellt. IoC / DI-Container wie Castle Windsor, Unity sind Tools (Bibliotheken), die zur Bereitstellung von IoC verwendet werden können. Diese Tools bieten erweiterte Funktionen, die über das einfache Abhängigkeitsmanagement hinausgehen, einschließlich Lebensdauer, AOP / Interception, Richtlinien usw.

  2. ein. Verhindert, dass eine Komponente für die Verwaltung ihrer Abhängigkeiten verantwortlich ist.
    b. Bietet die Möglichkeit, Abhängigkeitsimplementierungen in verschiedenen Umgebungen auszutauschen.
    c. Ermöglicht das Testen einer Komponente durch Verspotten von Abhängigkeiten.
    d. Bietet einen Mechanismus zum Freigeben von Ressourcen in einer Anwendung.

  3. ein. Kritisch bei testgetriebener Entwicklung. Ohne IoC kann das Testen schwierig sein, da die zu testenden Komponenten stark an den Rest des Systems gekoppelt sind.
    b. Kritisch bei der Entwicklung modularer Systeme. Ein modulares System ist ein System, dessen Komponenten ausgetauscht werden können, ohne dass eine Neukompilierung erforderlich ist.
    c. Kritisch, wenn es viele Querschnittsthemen gibt, die insbesondere in einer Unternehmensanwendung berücksichtigt werden müssen.


2
Bei IoC geht es eigentlich nicht hauptsächlich um die Verwaltung von Abhängigkeiten. Weitere Informationen finden Sie unter martinfowler.com/articles/injection.html#InversionOfControl . Beachten Sie insbesondere den Teil "Inversion of Control" ist ein zu allgemeiner Begriff, und daher finden ihn die Leute verwirrend. Infolgedessen diskutieren wir viel mit verschiedenen IoC-Befürwortern entschied sich für den Namen Dependency Injection ".
Rogério

26

Beantworte nur den ersten Teil. Was ist es?

Inversion of Control (IoC) bedeutet, Instanzen von Abhängigkeiten zuerst und letztere Instanz einer Klasse zu erstellen (optional durch den Konstruktor einzufügen), anstatt zuerst eine Instanz der Klasse und dann die Klasseninstanz Instanzen von Abhängigkeiten zu erstellen. Somit kehrt die Umkehrung der Steuerung den Steuerungsfluss des Programms um. Anstatt dass der Angerufene den Kontrollfluss steuert (während er Abhängigkeiten erstellt), steuert der Aufrufer den Kontrollfluss des Programms .


Es geht nicht um Klassen- oder Objekterstellung, überprüfen Sie diese martinfowler.com/articles/injection.html#InversionOfControl
Raghvendra Singh

22

Ich werde mein einfaches Verständnis dieser beiden Begriffe aufschreiben:

For quick understanding just read examples*

Abhängigkeitsinjektion (DI):
Abhängigkeitsinjektion bedeutet im Allgemeinen, ein Objekt, von dem die Methode abhängt, als Parameter an eine Methode zu übergeben, anstatt dass die Methode das abhängige Objekt erstellt .
In der Praxis bedeutet dies, dass die Methode nicht direkt von einer bestimmten Implementierung abhängt. Jede Implementierung, die die Anforderungen erfüllt, kann als Parameter übergeben werden.

Mit diesen Objekten können Sie ihre Abhängigkeiten erkennen. Und der Frühling macht es verfügbar.
Dies führt zu einer lose gekoppelten Anwendungsentwicklung.

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

IoC-Container (Inversion of Control):
Dies ist ein allgemeines Merkmal von Frameworks. IOC verwaltet Java-Objekte
- von der Instanziierung bis zur Zerstörung über seine BeanFactory.
-Java-Komponenten, die vom IoC-Container instanziiert werden, werden als Beans bezeichnet. Der IoC-Container verwaltet den Umfang, die Lebenszyklusereignisse und alle AOP-Funktionen eines Beans, für die er konfiguriert und codiert wurde.

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.

Durch die Implementierung von Inversion of Control erhält ein Software- / Objektkonsument mehr Steuerelemente / Optionen für die Software / Objekte, anstatt gesteuert zu werden oder weniger Optionen zu haben.

Die Umkehrung der Kontrolle als Konstruktionsrichtlinie dient folgenden Zwecken:

Es gibt eine Entkopplung der Ausführung einer bestimmten Aufgabe von der Implementierung.
Jedes Modul kann sich auf das konzentrieren, wofür es entwickelt wurde.
Module machen keine Annahmen darüber, was andere Systeme tun, sondern verlassen sich auf ihre Verträge.
Das Ersetzen von Modulen hat keine Nebenwirkungen auf andere Module.
Ich werde die Dinge hier abstrakt halten. Sie können die folgenden Links besuchen, um ein detailliertes Verständnis des Themas zu erhalten.
Eine gute Lektüre mit Beispiel

Ausführliche Erklärung


17

Ich stimme NilObject zu , möchte aber noch Folgendes hinzufügen:

Wenn Sie feststellen, dass Sie eine ganze Methode kopieren und nur einen kleinen Teil des Codes ändern, können Sie in Betracht ziehen, ihn mit Umkehrung der Kontrolle anzugehen

Wenn Sie feststellen, dass Sie Code kopieren und einfügen, machen Sie fast immer etwas falsch. Einmal und nur einmal als Gestaltungsprinzip kodifiziert .


17

Aufgabe 1 besteht beispielsweise darin, ein Objekt zu erstellen. Ohne IOC-Konzept sollte Aufgabe Nr. 1 vom Programmierer ausgeführt werden. Mit dem IOC-Konzept würde Aufgabe Nr. 1 vom Container ausgeführt.

Kurz gesagt, die Steuerung wird vom Programmierer zum Container invertiert. Es wird also als Umkehrung der Kontrolle bezeichnet.

Ich habe hier ein gutes Beispiel gefunden .


Ein Container ist ein Konzept in IoC, bei dem sich das Objektmodell, einschließlich Abhängigkeiten (Beziehungen zwischen "Benutzer" -Objekt und "verwendetem" Objekt) und Objektinstanzen, befindet und verwaltet wird - z. B. enthalten. Der Container wird normalerweise von einem IoC-Framework wie Spring bereitgestellt. Stellen Sie sich das als Laufzeit-Repository für die Objekte vor, aus denen Ihre Anwendung besteht.
Der Awnry Bär

17

Nehmen wir an, wir treffen uns in einem Hotel.

Viele Menschen, viele Karaffen Wasser, viele Plastikbecher.

Wenn jemand trinken will, füllt sie eine Tasse, trinkt und wirft eine Tasse auf den Boden.

Nach einer Stunde oder so haben wir einen Boden mit Plastikbechern und Wasser bedeckt.

Kontrolle umkehren lassen.

Das gleiche Treffen am gleichen Ort, aber anstelle von Plastikbechern haben wir einen Kellner mit einem Glasbecher (Singleton)

und sie bietet den Gästen ständig das Trinken an.

Wenn jemand trinken will, holt sie aus dem Kellnerglas, trinkt und gibt es an den Kellner zurück.

Abgesehen von der Frage der hygienischen, letzten Form der Kontrolle des Trinkprozesses ist dies viel effektiver und wirtschaftlicher.

Und genau das macht der Spring (ein weiterer IoC-Container, zum Beispiel: Guice). Anstatt die Anwendung mit dem neuen Schlüsselwort (Plastikbecher nehmen) erstellen zu lassen, was sie benötigt, bietet der Spring IoC-Container jederzeit die gleiche Instanz (Singleton) des benötigten Objekts (Glas Wasser) an.

Denken Sie an sich selbst als Organisator eines solchen Treffens. Sie benötigen den Weg, um dies der Hotelverwaltung mitzuteilen

Die Mitglieder des Treffens benötigen ein Glas Wasser, aber kein Kinderspiel.

Beispiel:-

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

}

Nützliche Links:-


Sind Singletons keine statischen Objekte?
Gokigooooks

16

Es scheint, dass das verwirrendste an "IoC", dem Akronym und dem Namen, für den es steht, ist, dass es zu glamourös für einen Namen ist - fast ein Geräuschname.

Brauchen wir wirklich einen Namen, um den Unterschied zwischen prozeduraler und ereignisgesteuerter Programmierung zu beschreiben? OK, wenn wir müssen, aber müssen wir einen brandneuen "überlebensgroßen" Namen auswählen, der mehr verwirrt als löst?


1
IoC! = Ereignisgesteuert. Ähnlichkeiten (und in einigen Fällen überschneiden sich), aber sie sind im Prinzip nicht dasselbe Paradigma.
Der Awnry Bär

Gute Frage. Ereignisgesteuerte Programmierung ist sicherlich IoC. Wir schreiben Event-Handler und sie werden aus der Event-Schleife aufgerufen. IoC ist jedoch ein allgemeineres Konzept als ereignisgesteuerte Programmierung. Wenn Sie eine Methode in der Unterklasse überschreiben, handelt es sich auch um eine Art IoC. Sie schreiben einen Code, der aufgerufen wird, wenn die entsprechende Referenz (Instanz) verwendet wird.
vi.su.

15

Die Umkehrung der Kontrolle erfolgt, wenn Sie zum Lebensmittelgeschäft gehen und Ihre Frau Ihnen die Liste der zu kaufenden Produkte gibt.

In Bezug auf die Programmierung hat sie eine Rückruffunktion getProductList()an die Funktion übergeben, die Sie ausführen - doShopping().

Der Benutzer der Funktion kann einige Teile davon definieren, wodurch sie flexibler wird.


5
Meine Frau kauft normalerweise bei mir ein, aber ich stimme dieser Aussage zu.
ha9u63ar

1
@ ha9u63ar Deine Frau kauft bei dir ein? Nun, das nennt man dann Aggregation.
Julian

2
Wenn sie das Geld auch gibt, heißt es DI.
San

1
Das Wort Inversion - verkehrt herum - kam von, wenn Ihre Frau anruft getProductList(), müssen Sie die Quelle für Geld finden, bedeutet, dass die Kontrolle an Ihrer Seite ist. Im Falle einer Inversion wird sie kontrollieren, dh das Geld, das sie auch zum Kauf bereitstellt.
San

13

Ich habe hier ein sehr klares Beispiel gefunden, das erklärt, wie die 'Steuerung invertiert wird'.

Klassischer Code (ohne Abhängigkeitsinjektion)

So funktioniert ein Code, der DI nicht verwendet, ungefähr:

  • Anwendung benötigt Foo (zB einen Controller), also:
  • Anwendung erstellt Foo
  • Anwendung ruft Foo auf
    • Foo braucht Bar (zB einen Service), also:
    • Foo schafft Bar
    • Foo ruft Bar an
      • Bar braucht Bim (einen Service, ein Repository, ...), also:
      • Bar erstellt Bim
      • Bar macht etwas

Verwenden der Abhängigkeitsinjektion

So funktioniert ein Code mit DI ungefähr:

  • Anwendung braucht Foo, die Bar braucht, die Bim braucht, also:
  • Anwendung erstellt Bim
  • Anwendung erstellt Bar und gibt es Bim
  • Anwendung erstellt Foo und gibt es Bar
  • Anwendung ruft Foo auf
    • Foo ruft Bar an
      • Bar macht etwas

Die Steuerung der Abhängigkeiten wird von einem Aufruf zu einem Aufruf umgekehrt.

Welche Probleme löst es?

Die Abhängigkeitsinjektion erleichtert den Austausch mit der unterschiedlichen Implementierung der injizierten Klassen. Während des Unit-Tests können Sie eine Dummy-Implementierung einfügen, was das Testen erheblich erleichtert.

Beispiel: Angenommen, Ihre Anwendung speichert die vom Benutzer hochgeladene Datei in Google Drive. Mit DI sieht Ihr Controller-Code möglicherweise folgendermaßen aus:

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) {}
}

Wenn sich Ihre Anforderungen ändern, werden Sie anstelle von GoogleDrive aufgefordert, die Dropbox zu verwenden. Sie müssen nur eine Dropbox-Implementierung für das StorageServiceInterface schreiben. Sie müssen keine Änderungen am Controller vornehmen, solange die Dropbox-Implementierung dem StorageServiceInterface entspricht.

Während des Testens können Sie das Modell für das StorageServiceInterface mit der Dummy-Implementierung erstellen, wobei alle Methoden null (oder einen vordefinierten Wert gemäß Ihrer Testanforderung) zurückgeben.

Wenn Sie stattdessen die Controller-Klasse hatten, um das Speicherobjekt mit dem folgenden newSchlüsselwort zu erstellen:

class SomeController
{
    private $storage;

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

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

Wenn Sie mit der Dropbox-Implementierung ändern möchten, müssen Sie alle Zeilen ersetzen, in denen das newGoogleDriveService-Objekt erstellt wurde, und den DropboxService verwenden. Außerdem erwartet der Konstruktor beim Testen der SomeController-Klasse immer, dass die GoogleDriveService-Klasse und die tatsächlichen Methoden dieser Klasse ausgelöst werden.

Wann ist es angebracht und wann nicht? Meiner Meinung nach verwenden Sie DI, wenn Sie glauben, dass es alternative Implementierungen einer Klasse gibt (oder geben kann).


Dies sollte die richtigste Antwort sein, da sie als einzige erklärt, wie die "Steuerung" invertiert wird.
Yarimadam

beste Erklärung bisher
Ali80

12

Eine sehr einfache schriftliche Erklärung finden Sie hier

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

Es sagt -

"Jede nicht triviale Anwendung besteht aus zwei oder mehr Klassen, die zusammenarbeiten, um eine Geschäftslogik auszuführen. Traditionell ist jedes Objekt dafür verantwortlich, seine eigenen Verweise auf die Objekte zu erhalten, mit denen es zusammenarbeitet (seine Abhängigkeiten) Objekte erhalten ihre Abhängigkeiten zum Zeitpunkt der Erstellung von einer externen Entität, die jedes Objekt im System koordiniert. Mit anderen Worten, Abhängigkeiten werden in Objekte eingefügt. "


12

Die Inversion der Steuerung ist ein generisches Prinzip, während die Abhängigkeitsinjektion dieses Prinzip als Entwurfsmuster für die Objektdiagrammkonstruktion realisiert (dh die Konfiguration steuert, wie die Objekte aufeinander verweisen, anstatt dass das Objekt selbst steuert, wie die Referenz auf ein anderes Objekt abgerufen wird).

Wenn wir Inversion of Control als Entwurfsmuster betrachten, müssen wir uns ansehen, was wir invertieren. Die Abhängigkeitsinjektion kehrt die Steuerung zum Erstellen eines Diagramms von Objekten um. Wenn es in Laienform gesagt wird, impliziert die Umkehrung der Kontrolle eine Änderung des Kontrollflusses im Programm. Z.B. In der herkömmlichen eigenständigen App haben wir die Hauptmethode, mit der das Steuerelement an andere Bibliotheken von Drittanbietern übergeben wird (falls wir die Funktion der Bibliothek von Drittanbietern verwendet haben), aber durch Umkehrung des Steuerelements wird das Steuerelement vom Bibliothekscode eines Drittanbieters auf unseren Code übertragen , da wir den Service einer Drittanbieter-Bibliothek in Anspruch nehmen. Es gibt jedoch andere Aspekte, die innerhalb eines Programms invertiert werden müssen - z. B. das Aufrufen von Methoden und Threads, um den Code auszuführen.

Für diejenigen, die mehr über Inversion of Control erfahren möchten, wurde ein Artikel veröffentlicht, der ein vollständigeres Bild von Inversion of Control als Entwurfsmuster enthält (OfficeFloor: Verwenden von Office-Mustern zur Verbesserung des Software-Designs http://doi.acm.org/10.1145/). 2739011.2739013 mit einer kostenlosen Kopie zum Herunterladen unter http://www.officefloor.net/about.html ).

Was identifiziert wird, ist die folgende Beziehung:

Inversion der Kontrolle (für Methoden) = Abhängigkeit (Zustand) Injektion + Fortsetzung Injektion + Thread-Injektion

Zusammenfassung der obigen Beziehung für Inversion of Control verfügbar - http://dzone.com/articles/inversion-of-coupling-control


Dies ist eine sehr klare Antwort. Danke für die Erklärung.
KunYu Tsai

11

Bei IoC geht es darum, die Beziehung zwischen Ihrem Code und dem Code eines Drittanbieters (Bibliothek / Framework) umzukehren:

  • In der normalen S / W-Entwicklung schreiben Sie die main () -Methode und rufen "library" -Methoden auf. Sie haben die Kontrolle :)
  • In IoC steuert das "Framework" main () und ruft Ihre Methoden auf. Das Framework hat die Kontrolle :(

Bei DI (Dependency Injection) geht es darum, wie das Steuerelement in der Anwendung fließt. Herkömmliche Desktop-Anwendungen hatten einen Kontrollfluss von Ihrer Anwendung (main () -Methode) zu anderen Bibliotheksmethodenaufrufen. Wenn der DI-Kontrollfluss jedoch invertiert ist, kümmert sich das Framework darum, Ihre App zu starten, zu initialisieren und Ihre Methoden bei Bedarf aufzurufen.

Am Ende gewinnt man immer :)


10

Ich mag diese Erklärung: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

Es beginnt einfach und zeigt auch Codebeispiele.

Geben Sie hier die Bildbeschreibung ein

Der Verbraucher X benötigt die konsumierte Klasse Y, um etwas zu erreichen. Das ist alles gut und natürlich, aber muss X wirklich wissen, dass es Y verwendet?

Ist es nicht genug, dass X weiß, dass es etwas verwendet, das das Verhalten, die Methoden, Eigenschaften usw. von Y hat, ohne zu wissen, wer das Verhalten tatsächlich implementiert?

Durch Extrahieren einer abstrakten Definition des von X in Y verwendeten Verhaltens, wie unten dargestellt, und Ermöglichen, dass der Verbraucher X eine Instanz davon anstelle von Y verwendet, kann er weiterhin das tun, was er tut, ohne die Einzelheiten über Y kennen zu müssen.

Geben Sie hier die Bildbeschreibung ein

In der obigen Abbildung implementiert Y I und X verwendet eine Instanz von I. Während es durchaus möglich ist, dass X immer noch Y verwendet, ist es interessant, dass X das nicht weiß. Es weiß nur, dass es etwas verwendet, das I implementiert.

Lesen Sie den Artikel für weitere Informationen und eine Beschreibung der Vorteile wie:

  • X ist nicht mehr von Y abhängig
  • Flexibler kann die Implementierung zur Laufzeit entschieden werden
  • Isolierung der Codeeinheit, einfacheres Testen

...


Der Link ist sehr hilfreich. Wirklich danke :)
M Fuat NUROĞLU

10

Ich verstehe, dass die Antwort hier bereits gegeben wurde. Aber ich denke immer noch, dass einige Grundlagen über die Umkehrung der Kontrolle hier für zukünftige Leser ausführlich diskutiert werden müssen.

Inversion of Control (IoC) basiert auf einem sehr einfachen Prinzip namens Hollywood-Prinzip . Und es sagt das,

Rufen Sie uns nicht an, wir rufen Sie an

Was es bedeutet ist, dass Sie nicht nach Hollywood gehen, um Ihren Traum zu erfüllen. Wenn Sie es wert sind, wird Hollywood Sie finden und Ihren Traum wahr werden lassen. Ziemlich umgekehrt, oder?

Wenn wir jetzt über das Prinzip der IoC diskutieren, vergessen wir das Hollywood. Für IoC muss es drei Elemente geben, ein Hollywood, Sie und eine Aufgabe, die Ihren Traum erfüllen möchte.

In unserer Programmierwelt repräsentiert Hollywood ein generisches Framework (möglicherweise von Ihnen oder einer anderen Person geschrieben), Sie repräsentieren den Benutzercode, den Sie geschrieben haben, und die Aufgabe repräsentiert das, was Sie mit Ihrem Code erreichen möchten. Jetzt lösen Sie Ihre Aufgabe nie mehr selbst aus, nicht in IoC! Vielmehr haben Sie alles so gestaltet, dass Ihr Framework Ihre Aufgabe für Sie auslöst. So haben Sie ein wiederverwendbares Framework erstellt, das jemanden zum Helden oder einen anderen zum Bösewicht machen kann. Aber dieser Rahmen ist immer verantwortlich, er weiß, wann er jemanden auswählen muss und dass jemand nur weiß, was er sein will.

Ein reales Beispiel wäre hier gegeben. Angenommen, Sie möchten eine Webanwendung entwickeln. Sie erstellen also ein Framework, das alle gängigen Aufgaben einer Webanwendung behandelt, z. B. die Bearbeitung von http-Anforderungen, das Erstellen von Anwendungsmenüs, das Bereitstellen von Seiten, das Verwalten von Cookies, das Auslösen von Ereignissen usw.

Und dann lassen Sie einige Hooks in Ihrem Framework, in denen Sie weitere Codes einfügen können, um benutzerdefinierte Menüs, Seiten, Cookies oder das Protokollieren einiger Benutzerereignisse usw. zu generieren. Bei jeder Browseranforderung wird Ihr Framework ausgeführt und führt Ihre benutzerdefinierten Codes aus, wenn diese verknüpft sind, und stellt sie dann wieder bereit zum Browser.

Die Idee ist also ziemlich einfach. Anstatt eine Benutzeranwendung zu erstellen, die alles steuert, erstellen Sie zuerst ein wiederverwendbares Framework, das alles steuert. Dann schreiben Sie Ihre benutzerdefinierten Codes und hängen sie an das Framework an, um diese rechtzeitig auszuführen.

Laravel und EJB sind Beispiele für solche Frameworks.

Referenz:

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

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


1
Die am besten geeignete Antwort habe ich hier gefunden.
Blueray

8

Programmieren sprechen

IoC in einfachen Worten: Es ist die Verwendung von Interface als Mittel für bestimmte Dinge (z. B. ein Feld oder einen Parameter) als Platzhalter, der von einigen Klassen verwendet werden kann. Es ermöglicht die Wiederverwendbarkeit des Codes.

Nehmen wir zum Beispiel an, wir haben zwei Klassen: Hund und Katze . Beide haben die gleichen Eigenschaften / Zustände: Alter, Größe, Gewicht. Anstatt eine Serviceklasse namens DogService und CatService zu erstellen, kann ich eine einzige Serviceklasse namens AnimalService erstellen , mit der Dog und Cat nur verwendet werden können, wenn sie die Schnittstelle IAnimal verwenden .

Pragmatisch gesehen hat es jedoch einige Rückschläge.

a) Die meisten Entwickler wissen nicht, wie sie es verwenden sollen . Zum Beispiel kann ich eine Klasse namens erstellen Kunden und ich kann automatisch erstellen (mit den Tools der IDE) eine Schnittstelle namens ICustomer . Es ist also nicht selten, einen Ordner mit Klassen und Schnittstellen zu finden, unabhängig davon, ob die Schnittstellen wiederverwendet werden oder nicht. Es heißt BLOATED. Einige Leute könnten argumentieren, dass "wir es in Zukunft vielleicht nutzen könnten". : - |

b) Es gibt einige Einschränkungen. Lassen Sie uns zum Beispiel über den Fall von Hund und Katze sprechen und ich möchte einen neuen Dienst (Funktionalität) nur für Hunde hinzufügen. Angenommen, ich möchte die Anzahl der Tage berechnen, die ich zum Trainieren eines Hundes benötige ( trainDays()). Für Katzen ist es nutzlos, Katzen können nicht trainiert werden (ich scherze).

b.1) Wenn ich trainDays()den Service AnimalService hinzufüge , funktioniert er auch mit Katzen und ist überhaupt nicht gültig.

b.2) Ich kann eine Bedingung hinzufügen, in der trainDays()ausgewertet wird, welche Klasse verwendet wird. Aber es wird die IoC vollständig brechen.

b.3) Ich kann eine neue Serviceklasse namens DogService nur für die neue Funktionalität erstellen . Dies erhöht jedoch die Wartbarkeit des Codes, da wir zwei Serviceklassen (mit ähnlichen Funktionen) für Dog haben und es schlecht ist.


Über aufgeblähte Klassen / Schnittstellen: Sie müssen nicht immer jede einzelne Schnittstelle wiederverwenden. Manchmal ist es einfach sinnvoll, eine große Schnittstelle in viele kleinere aufzuteilen, um die Funktionsgrenzen zu erkennen. Kleinere Schnittstellen lassen sich auch leichter in anderen Implementierungen wiederverwenden. Außerdem werden Sie dazu ermutigt, auf einer Schnittstelle zu codieren, wo immer dies sinnvoll ist. Betrachten Sie "Schnittstellentrennung". Nur weil Sie eine Schnittstelle verwenden, bedeutet dies nicht, dass Sie entkoppelt sind. Eine einzelne Fettschnittstelle ist nutzlos. - Nur meine 2 Cent :)
MK

7

Ich habe viele Antworten darauf gelesen, aber wenn jemand immer noch verwirrt ist und einen Pluspunkt für Laien benötigt, um IoC zu erklären, ist dies meine Meinung:

Stellen Sie sich vor, Eltern und Kind sprechen miteinander.

Ohne IoC:

* Eltern : Sie können nur sprechen, wenn ich Ihnen Fragen stelle, und Sie können nur handeln, wenn ich Ihnen die Erlaubnis gebe.

Elternteil : Das heißt, Sie können mich nicht fragen, ob Sie essen, spielen, auf die Toilette gehen oder sogar schlafen können, wenn ich Sie nicht frage.

Elternteil : Möchtest du essen?

Kind : Nein.

Elternteil : Okay, ich komme wieder. Warte auf mich.

Kind : (Will spielen, aber da es keine Frage des Elternteils gibt, kann das Kind nichts tun).

Nach 1 Stunde...

Elternteil : Ich bin zurück. Willst du spielen?

Kind : Ja.

Elternteil : Erlaubnis erteilt.

Kind : (kann endlich spielen).

In diesem einfachen Szenario wird erklärt, dass das Steuerelement auf das übergeordnete Element zentriert ist. Die Freiheit des Kindes ist eingeschränkt und hängt stark von der Frage der Eltern ab. Das Kind kann NUR sprechen, wenn es zum Sprechen aufgefordert wird, und kann NUR handeln, wenn die Erlaubnis erteilt wird.

Mit IoC:

Das Kind hat jetzt die Möglichkeit, Fragen zu stellen, und die Eltern können mit Antworten und Berechtigungen antworten. Bedeutet einfach, dass die Steuerung invertiert ist! Das Kind kann nun jederzeit Fragen stellen, und obwohl es hinsichtlich der Berechtigungen immer noch eine Abhängigkeit vom Elternteil gibt, ist es nicht abhängig von den Mitteln zum Sprechen / Stellen von Fragen.

In technologischer Hinsicht ist dies der Interaktion zwischen Konsole / Shell / cmd und GUI sehr ähnlich. (Welches ist die Antwort von Mark Harrison über Nr. 2 Top-Antwort). In der Konsole sind Sie abhängig von dem, was Ihnen gefragt / angezeigt wird, und Sie können nicht zu anderen Menüs und Funktionen springen, ohne zuerst die Frage zu beantworten. nach einem strengen sequentiellen Fluss. (Programmatisch ist dies wie eine Methoden- / Funktionsschleife). Mit der GUI sind die Menüs und Funktionen jedoch übersichtlich und der Benutzer kann auswählen, was er benötigt, wodurch er mehr Kontrolle hat und weniger eingeschränkt ist. (Programmgesteuert haben Menüs einen Rückruf, wenn sie ausgewählt sind und eine Aktion ausgeführt wird.)


6

Bei der Umkehrung der Kontrolle geht es darum, die Kontrolle von der Bibliothek auf den Client zu übertragen. Es ist sinnvoller, wenn wir über einen Client sprechen, der einen Funktionswert (Lambda-Ausdruck) in eine Funktion höherer Ordnung (Bibliotheksfunktion) einfügt (übergibt), die das Verhalten der Bibliotheksfunktion steuert (ändert). Ein Client oder Framework, das Bibliotheksabhängigkeiten (die Verhalten übertragen) in Bibliotheken einfügt, kann ebenfalls als IoC betrachtet werden


5

Da es bereits viele Antworten auf die Frage gibt, aber keine von ihnen die Aufschlüsselung des Begriffs Inversionskontrolle zeigt, sehe ich die Möglichkeit, eine präzisere und nützlichere Antwort zu geben.

Inversion of Control ist ein Muster, das das Dependency Inversion Principle (DIP) implementiert. DIP gibt Folgendes an: 1. High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beides sollte von Abstraktionen abhängen (zB Schnittstellen). 2. Abstraktionen sollten nicht von Details abhängen. Details (konkrete Implementierungen) sollten von Abstraktionen abhängen.

Es gibt drei Arten der Umkehrung der Kontrolle:

Schnittstelleninversionsanbieter sollten keine Schnittstelle definieren. Stattdessen sollte der Verbraucher die Schnittstelle definieren und die Anbieter müssen sie implementieren. Durch die Schnittstelleninversion entfällt die Notwendigkeit, den Verbraucher jedes Mal zu ändern, wenn ein neuer Anbieter hinzugefügt wird.

Flussinversion Ändert die Steuerung des Flusses. Sie haben beispielsweise eine Konsolenanwendung, in der Sie aufgefordert wurden, viele Parameter einzugeben, und nach jedem eingegebenen Parameter müssen Sie die Eingabetaste drücken. Hier können Sie Flow Inversion anwenden und eine Desktop-Anwendung implementieren, in der der Benutzer die Reihenfolge der Parametereingabe auswählen, Parameter bearbeiten und im letzten Schritt nur einmal die Eingabetaste drücken muss.

Erstellungsinversion Sie kann anhand der folgenden Muster implementiert werden: Factory Pattern, Service Locator und Dependency Injection. Die Erstellungsinversion hilft dabei, Abhängigkeiten zwischen Typen zu beseitigen, die den Prozess der Erstellung von Abhängigkeitsobjekten außerhalb des Typs verschieben, der diese Abhängigkeitsobjekte verwendet. Warum sind Abhängigkeiten schlecht? Hier einige Beispiele: Die direkte Erstellung eines neuen Objekts in Ihrem Code erschwert das Testen. Es ist unmöglich, Referenzen in Assemblys ohne Neukompilierung zu ändern (Verstoß gegen das OCP-Prinzip). Sie können eine Desktop-Benutzeroberfläche nicht einfach durch eine Web-Benutzeroberfläche ersetzen.


3
  1. Also Nummer 1 oben . Was ist Umkehrung der Kontrolle?

  2. Wartung ist die Nummer eins, die es für mich löst. Es garantiert, dass ich Schnittstellen verwende, damit zwei Klassen nicht miteinander vertraut sind.

Durch die Verwendung eines Containers wie Castle Windsor werden Wartungsprobleme noch besser gelöst. Es ist fantastisch, eine Komponente, die in eine Datenbank geht, gegen eine Komponente auszutauschen, die dateibasierte Persistenz verwendet, ohne eine Codezeile zu ändern (Konfigurationsänderung, fertig).

Und sobald Sie sich mit Generika beschäftigen, wird es noch besser. Stellen Sie sich einen Nachrichtenverleger vor, der Datensätze empfängt und Nachrichten veröffentlicht. Es ist egal, was veröffentlicht wird, aber es benötigt einen Mapper, um etwas von einem Datensatz in eine Nachricht zu übertragen.

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

Ich habe es einmal geschrieben, aber jetzt kann ich viele Typen in diesen Code-Satz einfügen, wenn ich verschiedene Arten von Nachrichten veröffentliche. Ich kann auch Mapper schreiben, die einen Datensatz des gleichen Typs aufnehmen und sie verschiedenen Nachrichten zuordnen. Durch die Verwendung von DI mit Generika konnte ich sehr wenig Code schreiben, um viele Aufgaben zu erledigen.

Oh ja, es gibt Bedenken hinsichtlich der Testbarkeit, aber sie sind den Vorteilen von IoC / DI untergeordnet.

Ich liebe IoC / DI definitiv.

3 . Es wird angemessener, sobald Sie ein mittelgroßes Projekt mit etwas mehr Komplexität haben. Ich würde sagen, es wird angemessen, sobald Sie anfangen, Schmerzen zu fühlen.



3

Das Erstellen eines Objekts innerhalb einer Klasse wird als enge Kopplung bezeichnet. Spring entfernt diese Abhängigkeit, indem es einem Entwurfsmuster (DI / IOC) folgt. In welchem ​​Objekt der Klasse wird im Konstruktor übergeben, anstatt in der Klasse zu erstellen. Darüber hinaus geben wir im Konstruktor eine Referenzvariable für Superklassen an, um eine allgemeinere Struktur zu definieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.