Frage Was ist eine Abhängigkeitsinjektion?


Es wurden bereits einige Fragen zu bestimmten Fragen gestellt Abhängigkeitsspritzewie wann und mit welchen Frameworks. Jedoch,

Was ist eine Abhängigkeitsinjektion und wann / warum sollte oder sollte sie nicht verwendet werden?


2626
2017-09-25 00:28


Ursprung


Antworten:


Im Grunde, anstatt dass Ihre Objekte eine Abhängigkeit erzeugen oder ein Factory-Objekt bitten, eine für sie zu erstellen, übergeben Sie die benötigten Abhängigkeiten extern an das Objekt, und Sie machen es zu einem anderen Problem. Dieser "Jemand" ist entweder ein Objekt weiter oben im Abhängigkeitsdiagramm oder ein Abhängigkeitsinjektor (Framework), der das Abhängigkeitsdiagramm erstellt. Eine Abhängigkeit, wie ich sie hier verwende, ist jedes andere Objekt, auf das das aktuelle Objekt einen Bezug nehmen muss.

Einer der Hauptvorteile der Abhängigkeitsinjektion besteht darin, dass sie die Testpartien vereinfachen kann. Angenommen, Sie haben ein Objekt, das in seinem Konstruktor etwa so aussieht:

public SomeClass() {
    myObject = Factory.getObject();
}

Dies kann mühsam sein, wenn Sie nur einige Komponententests auf SomeClass ausführen möchten, insbesondere wenn myObject einen komplexen Festplatten- oder Netzwerkzugriff ausführt. Sie betrachten nun myObject, fangen aber auch irgendwie den Werksaufruf ab. Hart. Übergeben Sie das Objekt stattdessen als Argument an den Konstruktor. Jetzt haben Sie das Problem anderswo verschoben, aber das Testen kann viel einfacher werden. Machen Sie einfach einen Dummy myObject und übergeben Sie ihn. Der Konstruktor würde jetzt ungefähr wie folgt aussehen:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Dies ist ein Stil der Abhängigkeitsinjektion - über den Konstruktor. Mehrere Mechanismen sind möglich.

  • Wie in den Kommentaren erwähnt, besteht eine übliche Alternative darin, einen Do-nothing-Konstruktor zu definieren und die Abhängigkeiten über Eigenschaften-Setzer (h / t @ MikeVella) zu injizieren.
  • Martin Fowler dokumentiert eine dritte Alternative (h / t @MarcDix), in der Klassen explizit eine Schnittstelle für die Abhängigkeiten implementieren, die sie injizieren möchten.

Wenn keine Abhängigkeitsinjektion verwendet wird (z. B. in Klassen, die in ihren Konstruktoren usw. zu viel arbeiten), wird es tendenziell schwieriger, Komponenten in Komponententests zu isolieren.

Zurück im Jahr 2013, als ich diese Antwort schrieb, war dies ein großes Thema auf der Google-Test-Blog. Dies ist für mich immer noch der größte Vorteil, da Sie nicht immer die zusätzliche Flexibilität in Ihrem Laufzeitdesign benötigen (zum Beispiel für Service Locator oder ähnliche Muster), aber Sie müssen Ihre Klassen oft während des Tests isolieren können.


1633
2017-09-25 00:49



Die beste Definition, die ich bisher gefunden habe, ist eines von James Shore:

"Dependency Injection" ist ein 25-Dollar   Bezeichnung für ein 5-Cent-Konzept. [...]   Abhängigkeitsinjektion bedeutet, dass ein   Objekt seine Instanzvariablen. [...].

Es gibt ein Artikel von Martin Fowler das kann sich auch als nützlich erweisen.

Die Abhängigkeitsinjektion stellt im Grunde die Objekte bereit, die ein Objekt benötigt (seine Abhängigkeiten), anstatt es selbst konstruieren zu müssen. Es ist eine sehr nützliche Technik zum Testen, da Abhängigkeiten gespottet oder unterdrückt werden können.

Abhängigkeiten können auf viele Arten in Objekte injiziert werden (z. B. Konstruktorinjektion oder Setterinjektion). Man kann sogar spezialisierte Rahmen für die Abhängigkeitsinjektion (z.B. Spring) dazu verwenden, aber sie sind sicherlich nicht erforderlich. Sie benötigen diese Frameworks nicht, um eine Abhängigkeitsinjektion zu erhalten. Objekte (Abhängigkeiten) explizit zu instanziieren und weiterzuleiten ist genauso eine Injektion wie eine Injektion durch das Framework.


2058
2017-09-26 16:50



Ich fand dieses lustige Beispiel in Bezug auf lose Kopplung:

Jede Anwendung besteht aus vielen Objekten, die zusammenarbeiten, um einige nützliche Dinge zu tun. Traditionell ist jedes Objekt dafür verantwortlich, eigene Referenzen auf die abhängigen Objekte (Abhängigkeiten) zu erhalten, mit denen es zusammenarbeitet. Dies führt zu stark gekoppelten Klassen und schwer zu testendem Code.

Betrachten Sie zum Beispiel a Car Objekt.

EIN Car hängt davon ab, ob Räder, Motor, Kraftstoff, Batterie usw. laufen. Traditionell definieren wir die Marke solcher abhängigen Objekte zusammen mit der Definition des Car Objekt.

Ohne Abhängigkeitseinspritzung (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Hier das Car Objekt ist verantwortlich für die Erstellung der abhängigen Objekte.

Was, wenn wir den Typ des abhängigen Objekts ändern wollen Wheel - Nach dem Anfang NepaliRubberWheel() Einstiche? Wir müssen das Auto-Objekt mit seiner neuen Abhängigkeit say neu erstellen ChineseRubberWheel(), aber nur die Car Hersteller kann das tun.

Was macht das dann? Dependency Injection Tust du uns ...?

Bei Verwendung der Abhängigkeitsinjektion erhalten Objekte ihre Abhängigkeiten zur Laufzeit anstatt zur Kompilierzeit (Autoherstellungszeit). Damit können wir jetzt das ändern Wheel wann immer wir wollen. Hier das dependency (wheel) kann injiziert werden Car zur Laufzeit.

Nach der Verwendung der Abhängigkeitsinjektion:

Hier sind wir injizieren das Abhängigkeiten (Rad und Batterie) zur Laufzeit. Daher der Begriff: Abhängigkeitsspritze. 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Quelle: Verständnis der Abhängigkeitsinjektion


507
2018-05-22 04:01



Dependency Injection ist eine Vorgehensweise, bei der Objekte so entworfen werden, dass sie Instanzen der Objekte von anderen Codeabschnitten empfangen, anstatt sie intern zu erstellen. Dies bedeutet, dass jedes Objekt, das die Schnittstelle implementiert, die von dem Objekt benötigt wird, ersetzt werden kann, ohne den Code zu ändern, was das Testen vereinfacht und die Entkopplung verbessert.

Betrachten Sie zum Beispiel diese Klauseln:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

In diesem Beispiel wird die Implementierung von PersonService::addManager und PersonService::removeManager würde eine Instanz des GroupMembershipService benötigen, um seine Arbeit zu erledigen. Ohne Dependency Injection wäre die traditionelle Art, dies zu tun, die Instantiierung eines neuen GroupMembershipService im Konstruktor von PersonService und verwende dieses Instanzattribut in beiden Funktionen. Wenn jedoch der Konstruktor von GroupMembershipService hat mehrere Dinge, die es erfordert, oder noch schlimmer, es gibt einige Initialisierungs - "Setter", die auf dem aufgerufen werden müssen GroupMembershipService, der Code wächst ziemlich schnell, und der PersonServiceJetzt kommt es nicht nur auf die GroupMembershipService aber auch alles andere GroupMembershipService kommt drauf an. Außerdem ist die Verbindung zu GroupMembershipService ist fest in die PersonService was bedeutet, dass Sie nicht "dumm" a GroupMembershipService zu Testzwecken oder um ein Strategie-Muster in verschiedenen Teilen Ihrer Anwendung zu verwenden.

Mit Dependency Injection, anstatt die GroupMembershipService in deinem PersonService, würdest du es entweder an die PersonService Konstruktor oder fügen Sie eine Eigenschaft (Getter und Setter) hinzu, um eine lokale Instanz davon festzulegen. Dies bedeutet, dass Ihre PersonService muss sich nicht mehr darum kümmern, wie man ein GroupMembershipServiceEs akzeptiert nur die, die es gegeben hat, und arbeitet mit ihnen. Dies bedeutet auch, dass alles, was eine Unterklasse von GroupMembershipServiceoder implementiert die GroupMembershipService Schnittstelle kann in die "injiziert" werden PersonService, und das PersonService muss nicht über die Änderung wissen.


233
2017-09-25 06:49



Die akzeptierte Antwort ist eine gute - aber ich möchte hinzufügen, dass DI der klassischen Vermeidung von fest codierten Konstanten im Code sehr ähnlich ist.

Wenn Sie eine Konstante wie einen Datenbanknamen verwenden, verschieben Sie sie schnell aus dem Inneren des Codes in eine Konfigurationsdatei und übergeben eine Variable, die diesen Wert enthält, an die Stelle, an der sie benötigt wird. Der Grund dafür ist, dass sich diese Konstanten in der Regel häufiger ändern als der Rest des Codes. Zum Beispiel, wenn Sie den Code in einer Testdatenbank testen möchten.

DI ist analog dazu in der Welt der objektorientierten Programmierung. Die Werte dort anstelle von konstanten Literalen sind ganze Objekte - aber der Grund, den Code zu verschieben, der sie aus dem Klassencode erzeugt, ist ähnlich - die Objekte ändern sich häufiger als der Code, der sie verwendet. Ein wichtiger Fall, in dem eine solche Änderung erforderlich ist, sind Tests.


142
2018-01-06 18:33



Stellen wir uns vor, dass Sie angeln gehen wollen:

  • Ohne Abhängigkeitsinjektion müssen Sie sich um alles selbst kümmern. Sie müssen ein Boot finden, eine Angelrute kaufen, nach Köder suchen, usw. Natürlich ist es möglich, aber es bedeutet Ihnen viel Verantwortung. Software bedeutet, dass Sie nach all diesen Dingen suchen müssen.

  • Mit der Abhängigkeitsinjektion kümmert sich jemand anders um die Vorbereitung und stellt Ihnen die benötigte Ausrüstung zur Verfügung. Sie erhalten das Boot, die Angelrute und den Köder - alles gebrauchsfertig.


96
2017-10-22 04:47



Dies ist die einfachste Erklärung über Abhängigkeitsspritze und Dependency-Injektionsbehälter Die ich je gesehen habe:

Ohne Abhängigkeitsinjektion

  • Anwendung benötigt Foo (z. B. ein Controller), also:
  • Anwendung erstellt Foo
  • Anwendungsaufrufe Foo
    • Foo braucht Bar (z.B. eine Dienstleistung), also:
    • Foo erstellt Bar
    • Foo ruft Bar an
      • Bar braucht Bim (ein Service, ein Repository, …), damit:
      • Bar schafft Bim
      • Bar macht etwas

Mit Abhängigkeitsinjektion

  • Anwendung benötigt Foo, die Bar benötigt, die Bim benötigt, also:
  • Anwendung erstellt Bim
  • Anwendung erstellt Bar und gibt es Bim
  • Anwendung erstellt Foo und gibt es Bar
  • Anwendungsaufrufe Foo
    • Foo ruft Bar an
      • Bar macht etwas

Einen Dependency-Injektionscontainer verwenden

  • Anwendung braucht Foo so:
  • Anwendung bekommt Foo aus dem Container, also:
    • Container erstellt Bim
    • Container erstellt Bar und gibt ihm Bim
    • Container erstellt Foo und gibt es Bar
  • Anwendungsaufrufe Foo
    • Foo ruft Bar an
      • Bar macht etwas

Abhängigkeitsspritze und Abhängigkeit Injektionsbehälter sind verschiedene Dinge:

  • Dependency Injection ist eine Methode, um besseren Code zu schreiben
  • Ein DI-Container ist ein Werkzeug, um Abhängigkeiten zu injizieren

Sie benötigen keinen Container, um die Abhängigkeitsinjektion durchzuführen. Ein Container kann Ihnen jedoch helfen.


80
2018-05-05 11:53