Es wurden bereits mehrere Fragen zu Dependency Injection gestellt, z. B. wann man sie verwenden sollte und welche Frameworks es dafür gibt. Wie auch immer,
**Was ist Dependency Injection und wann/warum sollte man sie verwenden oder nicht?
Die beste Definition, die ich bisher gefunden habe, ist eine von James Shore:
"Dependency Injection" ist ein 25-Dollar Begriff für ein 5-Cent-Konzept. [...] Dependency Injection bedeutet, dass man einem Objekt seine Instanzvariablen. [...].
Es gibt einen Artikel von Martin Fowler, der sich ebenfalls als nützlich erweisen könnte.
Dependency Injection bedeutet im Grunde, 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 mockieren oder zu stubben.
Abhängigkeiten können auf viele Arten 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.
Dependency Injection ist die Übergabe von Abhängigkeiten an andere Objekte oder Framework (Dependency Injector).
Dependency Injection macht das Testen einfacher. Die Injektion kann durch den Konstruktor durchgeführt werden.
Der Konstruktor von "SomeClass()" sieht wie folgt aus:
public SomeClass() {
myObject = Factory.getObject();
}
Problem:
Wenn myObject
komplexe Aufgaben wie Festplatten- oder Netzwerkzugriff beinhaltet, ist es schwer, Unit-Tests für SomeClass()
durchzuführen. Programmierer müssen myObject
spiegeln und können den Factory-Aufruf abfangen.
Alternative Lösung:
myObject
als Argument an den Konstruktorpublic SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject
kann direkt übergeben werden, was das Testen erleichtert.
Ohne Dependency Injection ist es schwieriger, Komponenten in Unit-Tests zu isolieren.
Im Jahr 2013, als ich diese Antwort schrieb, war dies ein wichtiges Thema auf dem Google Testing Blog. Für mich ist dies 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 die Klassen während des Testens oft isolieren.
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.
Betrachten Sie zum Beispiel diese Clases:
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 würde die Implementierung von PersonService::addManager
und PersonService::removeManager
eine Instanz von GroupMembershipService
benötigen, um ihre Arbeit zu erledigen. Ohne Dependency Injection wäre der traditionelle Weg, dies zu tun, die Instanzierung eines neuen GroupMembershipService
im Konstruktor von PersonService
und die Verwendung dieses Instanzattributs in beiden Funktionen. Wenn jedoch der Konstruktor von GroupMembershipService
mehrere Dinge benötigt, oder schlimmer noch, es gibt einige Initialisierungs-"Setter", die auf GroupMembershipService
aufgerufen werden müssen, wächst der Code ziemlich schnell, und der PersonService
hängt jetzt nicht nur vom GroupMembershipService
ab, sondern auch von allem anderen, von dem GroupMembershipService
abhängt. Außerdem ist die Verknüpfung zum GroupMembershipService
im PersonService
fest einkodiert, was bedeutet, dass man keinen GroupMembershipService
zu Testzwecken oder zur Verwendung eines Strategiemusters in verschiedenen Teilen der Anwendung "nachbauen" kann.
Mit Dependency Injection, anstatt den GroupMembershipService
innerhalb Ihres PersonService
zu instanziieren, würden Sie ihn entweder an den PersonService
Konstruktor übergeben, oder eine Eigenschaft (getter und setter) hinzufügen, um eine lokale Instanz davon zu setzen. Das bedeutet, dass Ihr PersonService
sich nicht mehr darum kümmern muss, wie man einen GroupMembershipService
erstellt, er akzeptiert einfach die, die ihm gegeben werden, und arbeitet mit ihnen. 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
muss nichts von der Änderung wissen.