Die Inversion der Steuerung (IoC) kann beim ersten Auftreten ziemlich verwirrend sein.
- Was ist es?
- Welches Problem löst es?
- Wann ist es angebracht zu verwenden und wann nicht?
Die Inversion der Steuerung (IoC) kann beim ersten Auftreten ziemlich verwirrend sein.
Antworten:
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 TextEditor
und 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 TextEditor
Klasse direkt von der SpellChecker
Klasse abhängt .
Im zweiten Codebeispiel erstellen wir eine Abstraktion, indem wir die SpellChecker
Abhängigkeitsklasse in TextEditor
der 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 TextEditor
Klasse erstellt, die Kontrolle darüber, welche SpellChecker
Implementierung verwendet werden soll, da wir die Abhängigkeit in die TextEditor
Signatur einfügen.
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.
Was ist Umkehrung der Kontrolle?
Wenn Sie diese einfachen zwei Schritte ausführen, haben Sie die Kontrolle 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
what-to-do
undwhen-to-do
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.
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).
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:
Nachteile:
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 .
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
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 .
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 .
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:-
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?
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.
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.
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:
Verwenden der Abhängigkeitsinjektion
So funktioniert ein Code mit DI ungefähr:
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 new
Schlü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 new
GoogleDriveService-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).
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. "
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
Bei IoC geht es darum, die Beziehung zwischen Ihrem Code und dem Code eines Drittanbieters (Bibliothek / Framework) umzukehren:
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 :)
Ich mag diese Erklärung: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/
Es beginnt einfach und zeigt auch Codebeispiele.
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.
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:
...
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:
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.
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.)
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
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.
Also Nummer 1 oben . Was ist Umkehrung der Kontrolle?
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.
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.