3581 Stimmen

Was ist Dependency Injection?

Es wurden bereits mehrere Fragen zu folgenden Themen gestellt Dependency Injection wie z. B. wann sie zu verwenden ist und welche Rahmenbedingungen es dafür gibt. Wie auch immer,

Was ist Dependency Injection und wann und warum sollte sie eingesetzt werden?

0 Stimmen

Siehe meine Diskussion über Dependency Injection Hier .

44 Stimmen

Ich stimme den Kommentaren zu den Links zu. Ich kann verstehen, dass Sie vielleicht auf jemand anderen verweisen wollen. Aber fügen Sie zumindest hinzu, warum Sie sie verlinken und was diesen Link besser macht als die anderen Links, die ich mit Google finden könnte

0 Stimmen

@AR: Technisch gesehen, ist Dependency Injection no eine besondere Form von IoC. Vielmehr ist IoC eine Technik, die zur Bereitstellung von Dependency Injection verwendet wird. Es können auch andere Techniken für die Dependency Injection verwendet werden (obwohl IoC die einzige ist, die häufig verwendet wird), und IoC wird auch für viele andere Probleme verwendet.

2770voto

Thiago Arrais Punkte 31480

Die beste Definition, die ich bis jetzt gefunden habe, lautet einer von James Shore :

"Dependency Injection" ist ein 25-Dollar-Begriff Begriff für ein 5-Cent-Konzept. [...] Dependency Injection bedeutet, dass man einem Objekt seine Instanzvariablen. [...].

Es gibt ein Artikel von Martin Fowler die sich ebenfalls als nützlich erweisen können.

Bei der Dependency Injection geht es im Wesentlichen darum, die Objekte bereitzustellen, die ein Objekt benötigt (seine Abhängigkeiten), anstatt sie selbst zu konstruieren. Es ist eine sehr nützliche Technik für das Testen, da sie es ermöglicht, Abhängigkeiten zu mocked oder stubbed out zu sein.

Abhängigkeiten können auf verschiedene Weise in Objekte injiziert werden (z. B. durch Konstruktorinjektion oder Setterinjektion). Man kann sogar spezialisierte Dependency-Injection-Frameworks (z. B. Spring) verwenden, um dies zu tun, aber sie sind sicherlich nicht erforderlich. Man braucht diese Frameworks nicht, um Dependency Injection zu haben. Die explizite Instanziierung und Übergabe von Objekten (Abhängigkeiten) ist eine ebenso gute Injektion wie die Injektion durch ein Framework.

56 Stimmen

Mir gefällt die Erklärung des James-Artikels, vor allem das Ende: "Dennoch muss man sich über jeden Ansatz wundern, der aus drei Konzepten ('TripPlanner', 'CabAgency' und 'AirlineAgency') mehr als neun Klassen macht und dann Dutzende von Zeilen Glue-Code und Konfigurations-XML hinzufügt, bevor eine einzige Zeile Anwendungslogik geschrieben wurde." Das ist es, was ich (leider) sehr oft gesehen habe - dass Dependency Injection (die an sich gut ist, wie von ihm erklärt) missbraucht wird, um Dinge zu verkomplizieren, die einfacher hätten gemacht werden können - was damit endet, dass man "unterstützenden" Code schreibt ...

6 Stimmen

Re: "Das explizite Instanziieren und Übergeben von Objekten (Abhängigkeiten) ist eine ebenso gute Injektion wie die Injektion durch ein Framework.". Warum also haben die Leute Frameworks entwickelt, die das tun?

26 Stimmen

Aus demselben Grund, aus dem jedes Framework geschrieben wird (oder zumindest geschrieben werden sollte): weil es eine Menge an wiederholtem/Boilerplate-Code gibt, der geschrieben werden muss, sobald man eine gewisse Komplexität erreicht hat. Das Problem ist, dass die Leute oft zu einem Framework greifen, auch wenn es nicht unbedingt benötigt wird.

2148voto

wds Punkte 30993

Injektion von Abhängigkeiten gibt die Abhängigkeit an andere Objekte o Rahmenwerk ( Abhängigkeitsinjektor).

Dependency Injection erleichtert das Testen. Die Injektion kann durchgeführt werden durch Konstrukteur .

SomeClass() hat den folgenden Konstruktor:

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

Problem : Wenn myObject komplexe Aufgaben wie Festplatten- oder Netzwerkzugriff beinhaltet, ist es hart um Unit-Tests durchzuführen auf SomeClass() . Programmierer müssen spötteln myObject und könnte abfangen. den Werksbesuch.

Alternative Lösung :

  • Weitergabe myObject als Argument für den Konstruktor eingeben

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

myObject können direkt übergeben werden, was die Prüfung erleichtert.

  • Eine gängige Alternative ist die Definition einer Nichtsnutzkonstruktor . Dependency Injection kann über Setter erfolgen. (h/t @MikeVella).
  • Martin Fowler dokumentiert eine dritte Alternative (h/t @MarcDix), bei der Klassen implementieren explizit eine Schnittstelle für die Abhängigkeiten, die Programmierer einfügen möchten.

Ohne Dependency Injection ist es schwieriger, Komponenten bei Unit-Tests zu isolieren.

Im Jahr 2013, als ich diese Antwort schrieb, war dies ein wichtiges Thema auf der Google Testing Blog . Das ist für mich nach wie vor der größte Vorteil, da Programmierer nicht immer die zusätzliche Flexibilität in ihrem Laufzeitdesign benötigen (z. B. für Service Locator oder ähnliche Muster). Programmierer müssen oft die Klassen während des Testens isolieren.

29 Stimmen

Ich erkenne an, dass Ben Hoffsteins Verweis auf Martin Fowlers Artikel notwendig ist, da er auf ein "Muss" zu diesem Thema hinweist, aber ich akzeptiere die Antwort von wds, weil sie die Frage hier auf SO tatsächlich beantwortet.

137 Stimmen

+1 zur Erklärung und Motivation: die Erstellung von Objekten, von denen eine Klasse abhängt, zum Problem eines anderen zu machen . Man kann auch sagen, dass DI den Zusammenhalt der Klassen stärkt (sie haben weniger Verantwortung).

15 Stimmen

Sie sagen, die Abhängigkeit wird "in den Konstruktor" übergeben, aber so wie ich es verstehe, ist dies nicht streng wahr. Es ist immer noch Dependency Injection, wenn die Abhängigkeit als Eigenschaft festgelegt wird, nachdem das Objekt instanziiert wurde, richtig?

821voto

gtiwari333 Punkte 23343

_Ich fand dieses lustige Beispiel in Bezug auf lose Kopplung :_

Quelle: Verständnis der Injektion von Abhängigkeiten

Jede Anwendung besteht aus vielen Objekten, die miteinander zusammenarbeiten, um nützliche Aufgaben zu erfüllen. Traditionell ist jedes Objekt für die Beschaffung seiner eigenen Verweise auf die abhängigen Objekte (Abhängigkeiten) verantwortlich, mit denen es zusammenarbeitet. Dies führt zu stark gekoppelten Klassen und schwer zu testendem Code.

Nehmen wir zum Beispiel eine Car Objekt.

A Car von Rädern, Motor, Kraftstoff, Batterie usw. abhängt, um zu funktionieren. Traditionell definieren wir die Marke solcher abhängigen Objekte zusammen mit der Definition der Car Objekt.

Ohne Dependency Injection (DI):

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

  //The rest
}

Hier ist die Car Objekt ist für die Erstellung der abhängigen Objekte zuständig.

Was ist, wenn wir den Typ des abhängigen Objekts ändern wollen - sagen wir Wheel - nach der anfänglichen NepaliRubberWheel() durchstochen? Wir müssen das Objekt Car mit seiner neuen Abhängigkeit neu erstellen, z. B. ChineseRubberWheel() sondern nur die Car Hersteller kann das tun.

Was bedeutet dann die Dependency Injection für uns tun...?

Bei der Verwendung von Dependency Injection werden die Objekte mit ihren Abhängigkeiten versehen zur Laufzeit und nicht zur Kompilierzeit (Herstellungszeit des Autos) . Damit können wir nun die Wheel wann immer wir wollen. Hier ist die dependency ( wheel ) kann injiziert werden in Car während der Laufzeit.

Nach der Verwendung von Dependency Injection:

Hier sind wir Einspeisung die Abhängigkeiten (Rad und Batterie) während der Laufzeit. Daher auch der Begriff : Dependency Injection. Normalerweise verlassen wir uns auf DI-Frameworks wie Spring, Guice, Weld, um die Abhängigkeiten zu erstellen und bei Bedarf zu injizieren.

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;
  }
}

Die Vorteile sind:

  • Entkopplung der Objekterzeugung (mit anderen Worten: Trennung der Nutzung von der Objekterzeugung)
  • Möglichkeit, Abhängigkeiten zu ersetzen (z. B. Rad, Batterie), ohne die Klasse zu ändern, die sie verwendet (Auto)
  • fördert den Grundsatz "Code to interface not to implementation".
  • die Möglichkeit, während des Tests eine Mock-Abhängigkeit zu erstellen und zu verwenden (wenn wir während des Tests ein Mock von Wheel anstelle einer echten Instanz verwenden wollen).

29 Stimmen

So wie ich das verstehe, können wir, anstatt ein neues Objekt als Teil eines anderen Objekts zu instanziieren, das besagte Objekt injizieren, wenn und falls es benötigt wird, und so die Abhängigkeit des ersten Objekts von diesem entfernen. Ist das richtig?

0 Stimmen

Ich habe dies hier am Beispiel eines Cafés beschrieben: digigene.com/design-patterns/dependency-injection-coffeeshop

13 Stimmen

Diese Analogie gefällt mir sehr gut, weil sie einfaches Englisch mit einer einfachen Analogie verwendet. Angenommen, ich bin Toyota und habe bereits zu viel Geld und Arbeitskraft in die Herstellung eines Autos vom Entwurf bis zur Montage investiert. Wenn es bereits namhafte Reifenhersteller gibt, warum sollte ich dann mit der Herstellung von Reifen ganz von vorne anfangen, d. h. new einen Reifen? Ich weiß es nicht. Alles, was ich tun muss, ist, bei ihnen zu kaufen (per Param injizieren), zu installieren und wah-lah! Um auf die Programmierung zurückzukommen: Angenommen, ein C#-Projekt muss eine vorhandene Bibliothek/Klasse verwenden, dann gibt es zwei Möglichkeiten, diese auszuführen/zu debuggen: 1) Hinzufügen eines Verweises auf das gesamte Projekt

293voto

Adam Ness Punkte 6118

Dependency Injection ist eine Praxis, bei der Objekte so entworfen werden, dass sie Instanzen der Objekte von anderen Teilen des Codes erhalten, anstatt sie intern zu konstruieren. Das bedeutet, dass jedes Objekt, das die für das Objekt erforderliche Schnittstelle implementiert, ohne Änderung des Codes ersetzt werden kann, was die Tests vereinfacht und die Entkopplung verbessert.

Nehmen wir zum Beispiel diese Fälle:

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 y PersonService::removeManager würde eine Instanz der GroupMembershipService um seine Arbeit zu tun. Ohne Dependency Injection wäre der traditionelle Weg, dies zu tun, die Instanziierung einer neuen GroupMembershipService im Konstruktor von PersonService und verwenden Sie dieses Instanzattribut in beiden Funktionen. Wenn jedoch der Konstruktor von GroupMembershipService mehrere Dinge benötigt, oder schlimmer noch, es gibt einige Initialisierungs-"Setter", die auf der GroupMembershipService wächst der Code ziemlich schnell, und die PersonService hängt jetzt nicht nur von der GroupMembershipService sondern auch alles andere, was GroupMembershipService hängt ab von. Außerdem ist die Verknüpfung mit GroupMembershipService ist fest in die Datei PersonService was bedeutet, dass man keine "Attrappe" für eine GroupMembershipService zu Testzwecken oder um ein Strategiemuster in verschiedenen Teilen Ihrer Anwendung zu verwenden.

Mit Dependency Injection wird anstelle der Instanziierung der GroupMembershipService innerhalb Ihrer PersonService würde man es entweder an den PersonService Konstruktor, oder fügen Sie eine Eigenschaft (Getter und Setter) hinzu, um eine lokale Instanz davon zu setzen. Dies bedeutet, dass Ihre PersonService muss sich nicht mehr darum kümmern, wie man eine GroupMembershipService Sie akzeptiert einfach die, die ihr gegeben werden, und arbeitet mit ihnen. Das bedeutet auch, dass alles, was eine Unterklasse von GroupMembershipService oder implementiert die GroupMembershipService Schnittstelle kann in die PersonService und die PersonService braucht von der Änderung nichts zu wissen.

36 Stimmen

Es wäre toll, wenn Sie das gleiche Codebeispiel NACH der Verwendung von DI geben könnten

1 Stimmen

"Das bedeutet auch, dass alles, was eine Unterklasse von GroupMembershipService ist oder die GroupMembershipService-Schnittstelle implementiert, in den PersonService "injiziert" werden kann und der PersonService nichts von der Änderung wissen muss." ... Das war ein sehr nützlicher Hinweis für mich - danke!

199voto

zby Punkte 2345

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

Wenn Sie eine Konstante wie den Namen einer Datenbank verwenden, verschieben Sie diese schnell aus dem Code in eine Konfigurationsdatei und übergeben eine Variable mit diesem Wert an die Stelle, an der er 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. Dort sind die Werte anstelle von konstanten Literalen ganze Objekte - aber der Grund, den Code, der sie erzeugt, aus dem Klassencode auszulagern, ist ähnlich - die Objekte ändern sich häufiger als der Code, der sie verwendet. Ein wichtiger Fall, in dem eine solche Änderung notwendig ist, sind Tests.

22 Stimmen

+1 "die Objekte ändern sich häufiger als der Code, der sie verwendet". Um zu verallgemeinern, fügen Sie eine Umleitung an Flusspunkten hinzu. Je nach Flusspunkt werden die Indirektionen mit unterschiedlichen Namen bezeichnet!!!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X