Die Wörter invert
oder control
werden überhaupt nicht verwendet, um Inversion of Control in den Definitionen zu definieren, die ich gesehen habe.
Definitionen
Wikipedia
Inversion of Control (IoC) ist eine Programmiertechnik, die hier als objektorientierte Programmierung ausgedrückt wird. Dabei wird die Objektkopplung zur Laufzeit durch ein Assembler-Objekt gebunden und ist zur Kompilierungszeit unter Verwendung der statischen Analyse in der Regel nicht bekannt. ~ http://en.wikipedia.org/wiki/Inversion_of_control
Martin Fowler
Inversion of Control ist ein in der Java-Community weit verbreitetes Muster, mit dem einfache Container verkabelt oder Komponenten aus verschiedenen Projekten zu einer zusammenhängenden Anwendung zusammengefügt werden können. ~ basiert auf http://www.martinfowler.com/articles/injection.html (umformuliert)
Warum heißt Inversion of Control Inversion of Control? Welche Steuerung wird invertiert und von wem? Gibt es eine Möglichkeit, die Umkehrung der Kontrolle mit der Terminologie zu definieren: invertieren und kontrollieren ?
quelle
Antworten:
Angenommen, Sie haben eine Art "Repository" -Klasse, und dieses Repository ist dafür verantwortlich, Ihnen Daten aus einer Datenquelle zu übergeben.
Das Repository kann selbst eine Verbindung zur Datenquelle herstellen. Was aber, wenn Sie damit eine Verbindung zur Datenquelle über den Konstruktor des Repositorys übergeben können?
Indem Sie dem Aufrufer erlauben, die Verbindung bereitzustellen, haben Sie die Abhängigkeit der Datenquellenverbindung von der Repository-Klasse entkoppelt, sodass jede Datenquelle mit dem Repository arbeiten kann, nicht nur mit dem vom Repository angegebenen.
Sie haben die Kontrolle umgekehrt, indem Sie die Verantwortung für das Herstellen der Verbindung von der Repository-Klasse an den Aufrufer übergeben haben.
Martin Fowler schlägt vor, den Begriff "Abhängigkeitsinjektion" zu verwenden, um diese Art der Inversion der Steuerung zu beschreiben, da die Inversion der Steuerung als Konzept breiter angewendet werden kann, als nur Abhängigkeiten in eine Konstruktormethode zu injizieren.
quelle
Ich denke, niemand kann es besser erklären als Martin Fowler, weiter unten in dem Artikel, mit dem Sie verlinkt sind .
Wie er in den obigen Abschnitten erklärt, ist dies nicht ganz derselbe Grund, aus dem der Begriff "Inversion of Control" entstand.
Aus diesem Grund prägt er den Begriff "Abhängigkeitsinjektion", um diese spezifische Implementierung von Inversion of Control zu behandeln.
Um es ein wenig zu verdeutlichen: Umkehrung der Kontrolle bedeutet alles, was die Kontrollstruktur eines Programms von der klassischen prozeduralen Gestaltung umkehrt.
In früheren Zeiten war ein Schlüsselbeispiel dafür, dass ein Framework die Kommunikation zwischen einer Benutzeroberfläche und Ihrem Code handhabte, anstatt Ihren Code für die direkte Generierung der Benutzeroberfläche zu belassen.
In jüngerer Zeit (als solche Frameworks so ziemlich dominierten und die Frage nicht mehr relevant war) war ein Beispiel die Umkehrung der Kontrolle über die Instanziierung von Objekten.
Fowler und andere entschieden, dass der Begriff Inversion of Control zu viele Techniken abdeckte, und wir brauchten einen neuen Begriff für das spezifische Beispiel der Instanziierung von Objekten (Abhängigkeitsinjektion), aber zu dem Zeitpunkt, als diese Vereinbarung getroffen worden war, den Ausdruck "IoC-Container" "war ausgezogen.
Dies trübt das Wasser sehr, da ein IoC-Container eine bestimmte Art von Abhängigkeitsinjektion ist, aber Abhängigkeitsinjektion ist eine bestimmte Art von Inversion der Steuerung. Dies ist der Grund, warum Sie so verwirrte Antworten erhalten, egal wo Sie hinschauen.
quelle
Hier sind die "regulären" Kontrollflussprogramme, die normalerweise befolgt werden:
Inversion of Control "kehrt" diesen Kontrollfluss um, was bedeutet, dass er auf den Kopf gestellt wird:
Diese letzte Zeile ist wichtig. Anstatt jemanden anzurufen, wenn Sie Lust dazu haben, ruft Sie jemand anders an, wenn er Lust dazu hat.
Ein häufiges Beispiel hierfür sind Web-Frameworks wie Rails. Sie definieren Controller, aber Sie entscheiden nicht, wann diese aufgerufen werden. Rails ruft sie an, wenn Bedarf besteht.
quelle
Es geht darum, wer die Instanziierung von Abhängigkeiten steuert.
Wenn eine Klasse / Methode eine andere Klasse (Abhängigkeit) verwenden muss, wird sie traditionell direkt von der Klasse / Methode instanziiert. Es steuert seine Abhängigkeiten.
Mit Inversion of Control (IoC) hat der Aufrufer die Abhängigkeit übergeben, wodurch die Abhängigkeit instanziiert wird. Der Aufrufer steuert die Abhängigkeiten.
Die Kontrolle darüber, wo eine Abhängigkeit instanziiert wird, wurde invertiert. Anstatt "unten" zu sein, wo der Code ist, der sie benötigt, wird sie "oben" instanziiert, wo der Code, der sie benötigt, aufgerufen wird.
quelle
Typischerweise ruft Code höherer Ebene Code niedrigerer Ebene auf (dh steuert diesen). Main () ruft function (), function () libraryFunction () auf.
Das kann invertiert werden, so dass die Bibliotheksfunktion der unteren Ebene Funktionen der höheren Ebene aufruft.
Warum würdest du das tun? Middleware. Manchmal möchten Sie die oberste und die unterste Ebene steuern, aber es gibt eine Menge Arbeit in der Mitte, die Sie einfach nicht tun möchten. Nehmen Sie die Implementierung von QuickSort in die C-Stdlib . Sie rufen QuickSort auf der obersten Ebene an. Sie übergeben qsort () einen Funktionszeiger auf Ihre eigene Funktion, der einen Komparator für jede beliebige Funktion implementiert. Wenn qsort () aufgerufen wird, ruft es diese Komparatorfunktion auf. qsort () steuert / ruft / steuert Ihre High-Level-Funktion.
quelle
Hier ist eine einfache Übersicht:
In früheren Zeiten gehörte die Kontrolle zuerst der Anwendung und dann dem Benutzer. Wenn die Anwendung etwas vom Benutzer benötigte, hielt sie an und fragte und ging dann zur nächsten Aufgabe über. Die Interaktion des Benutzers lieferte hauptsächlich Daten, anstatt zu steuern, was die Anwendung als Nächstes tat. Das ist uns heutzutage ein bisschen fremd, da wir diese Art von Verhalten nicht sehr oft sehen.
Wenn wir das umschalten und dem Benutzer die primäre Kontrolle geben, dann haben wir die Kontrolle invertiert. Dies bedeutet, dass der Benutzer nicht darauf wartet, dass die Anwendung etwas zu tun gibt, sondern darauf wartet, dass der Benutzer ihm etwas zu tun gibt. GUIs sind ein großartiges Beispiel dafür, und so ziemlich alles, was eine Ereignisschleife enthält, hat die Steuerung umgekehrt.
Beachten Sie, dass sich mein Beispiel auf der obersten Ebene befindet und dass dieses Konzept der Inversion der Steuerung auf verschiedene Steuerungsebenen innerhalb der Anwendung abstrahiert werden kann (dh Abhängigkeitsinjektion). Dies mag der Grund sein, warum es so schwierig ist, eine eindeutige Antwort zu erhalten.
quelle
Versuchen wir es anhand der beiden Beispiele zu verstehen.
Beispiel 1
In früheren Tagen haben Apps zum Generieren von Eingabeaufforderungen verwendet, um Benutzereingaben nacheinander zu akzeptieren. Heutzutage instanziieren UI-Frameworks verschiedene UI-Elemente, durchlaufen verschiedene Ereignisse dieser UI-Elemente (wie Mauszeiger, Mausklick usw.) und Benutzer- / Hauptprogramme stellen Hooks (zum Beispiel UI-Ereignis-Listener in Java) zum Abhören dieser Ereignisse bereit. Daher wird die "Steuerung" des Haupt-UI-Elementflusses vom Benutzerprogramm in das UI-Framework verschoben. In früheren Tagen war es im Anwenderprogramm.
Beispiel 2
Betrachten Sie die folgende Klasse
CustomerProcessor
:Wenn ich
processCustomer()
von einer Implementierung unabhängig sein möchtegetAllCusts()
, die nicht nur von der von bereitgestellt wirdSqlCustRepo
, muss ich die Leitung entfernen:SqlCustRepo custRepo = new SqlCustRepo()
und sie durch eine allgemeinere ersetzen, die in der Lage ist, verschiedene Arten der Implementierung zu akzeptieren, sodass dieprocessCustomers()
einfach funktioniert eine bereitgestellte Implementierung. Der obige Code (Instanziieren der erforderlichen KlasseSqlCustRepo
durch die Hauptprogrammlogik) ist ein traditioneller Weg und erreicht dieses Ziel der EntkopplungprocessCustomers()
von der Implementierung von nichtgetAllCusts()
. Bei der Inversion der Steuerung instanziiert der Container die erforderliche Implementierungsklasse (wie beispielsweise in der XML-Konfiguration angegeben) und fügt sie in die Hauptprogrammlogik ein, die gemäß den angegebenen Hooks gebunden wird (beispielsweise durch@Autowired
Annotation odergetBean()
Methode im Spring Framework).Mal sehen, wie das geht. Betrachten Sie den folgenden Code.
Config.xml
CustRepo.java
JsonCustRepo.java
App.java
Wir können auch haben
und
und wir müssen App.java nicht ändern.
Über dem Container (dem Spring Framework) muss die XML-Datei gescannt, die Bean eines bestimmten Typs instanziiert und in das Benutzerprogramm eingefügt werden. Benutzerprogramme haben keine Kontrolle darüber, welche Klasse instanziiert wird.
PS: IoC ist ein generisches Konzept und wird auf viele Arten erreicht. Die obigen Beispiele erreichen dies durch Abhängigkeitsinjektion.
Referenz: Martin Fowlers Artikel .
quelle