Was ist Dependency Injection?
-
02-07-2019 - |
Frage
Es wurden mehrere Fragen wurden bereits gebucht mit spezifischen Fragen zu Dependency Injection , wie wenn sie auf sie verwenden und welche Rahmenbedingungen gibt es dafür. Allerdings
Was Dependency Injection ist und wann / warum soll oder nicht verwendet werden?
Lösung
Dependency Injection vergeht Abhängigkeit zu anderen Objekte oder Rahmen (Abhängigkeit Injektor).
Dependency Injection macht das Testen einfacher. Die Injektion kann durch Konstruktor erfolgen.
SomeClass()
hat seinen Konstruktor wie folgt vor:
public SomeClass() {
myObject = Factory.getObject();
}
Problem :
Wenn myObject
komplexe Aufgaben wie Festplattenzugriff oder Netzwerkzugriff umfasst, ist es hart tun Unit-Test auf SomeClass()
. Programmierer haben myObject
zu verspotten und Macht abfangen die Fabrik Anruf.
Alternative Lösung :
- Passing
myObject
in als Argument an den Konstruktor
public SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject
kann direkt übergeben werden, das macht das Testen einfacher.
- Eine gemeinsame Alternative ist die Definition einer do-nothing Konstruktor . Dependency Injection kann durch Setzer durchgeführt werden. (H / t @MikeVella).
- Martin Fowler Dokumente eine dritte Alternative (h / t @MarcDix), wobei < strong> Klassen eine Schnittstelle explizit implementieren für die Abhängigkeiten Programmierer injiziert werden soll.
Es ist schwieriger zu Komponenten in Unit-Tests zu isolieren, ohne Dependency Injection.
Im Jahr 2013, als ich diese Antwort schrieb, war dies ein wichtiges Thema auf der Google Testing Blog . Es bleibt den größten Vorteil für mich als Programmierer nicht immer die zusätzliche Flexibilität in ihrer Laufzeit Design benötigen (zB für Service-Locator oder ähnliche Muster). Programmierer müssen häufig die Klassen während des Tests zu isolieren.
Andere Tipps
Die beste Definition, die ich bisher gefunden habe ist ein von James Shore :
"Dependency Injection" ist ein 25-Dollar Bezeichnung für ein 5-Cent-Konzept. [...] Dependency Injection bedeutet eine Angabe Objekt seine Instanzvariablen. [...].
Es gibt einen Artikel von Martin Fowler , die als nützlich erweisen können, auch.
Dependency Injection ist im Grunde die Objekte bereitstellt, die ein Objekt Bedürfnisse (seine Abhängigkeiten), anstatt sie selbst es zu konstruieren. Es ist eine sehr nützliche Technik für die Prüfung, da es Abhängigkeiten ermöglicht heraus verspottet oder gerodet werden.
Abhängigkeiten können in Objekte durch viele Mittel (wie Konstruktors Injektions- oder setter Injektion) injiziert werden. Man kann sogar spezielles Dependency Injection-Frameworks verwenden (z Frühling), das zu tun, aber sie sind sicherlich nicht erforderlich. Sie brauchen nicht diese Rahmenstrukturen Dependency Injection zu haben. Instanziieren und Objekte (Abhängigkeiten), die explizit genauso gut eine Injektion als Injektion von Rahmen ist.
Ich fand dieses lustige Beispiel in Bezug auf lose Kopplung :
Jede Anwendung wird von vielen Objekten zusammengesetzt, die miteinander zusammenarbeiten, einige nützliche Dinge auszuführen. Traditionell ist jedes Objekt für die eigenen Verweise auf die abhängigen Objekte (Abhängigkeiten) Erhalten sie arbeiten mit. Dies führt zu sehr gekoppelt Klassen und hart-zu-Test-Code.
Betrachten wir zum Beispiel ein Car
Objekt.
Ein Car
hängt von Rädern, Motor, Kraftstoff, Batterie usw. zu laufen. Traditionell definieren wir die Marke von solchen abhängigen Objekten zusammen mit der Definition des Car
Objekts.
Ohne Dependency Injection (DI):
class Car{
private Wheel wh = new NepaliRubberWheel();
private Battery bt = new ExcideBattery();
//The rest
}
Hier ist das Car
Objekt ist verantwortlich für die abhängigen Objekte zu schaffen.
Was passiert, wenn wir die Art der von ihr abhängigen Objekt ändern wollen - sagen Wheel
- nach den ersten NepaliRubberWheel()
Einstiche?
Wir müssen das Car-Objekt mit seinem neuen Abhängigkeiten neu sagen ChineseRubberWheel()
, sondern nur die Car
Hersteller kann das tun.
Und was macht den Dependency Injection
tut uns für ...?
Wenn Dependency Injection Verwendung von Objekten aufgrund ihrer Abhängigkeiten zur Laufzeit statt Kompilierung (Auto Herstellungszeit) .
Damit wir können nun die Wheel
ändern, wann immer wir wollen. Hier ist die dependency
(wheel
) in Car
zur Laufzeit injiziert werden.
Nach der Verwendung von Dependency Injection:
Wir sind hier injizierende Abhängigkeiten (Rad und Batterie) zur Laufzeit. Daher der Begriff:. Dependency Injection
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: Legendes Dependency Injection
Dependency Injection ist eine Praxis, wo Objekte in einer Weise ausgelegt werden, wo sie Instanzen der Objekte aus anderen Teile des Codes zu erhalten, anstatt sie intern zu konstruieren. Das bedeutet, dass jedes Objekt die Schnittstelle implementiert, die durch das Objekt benötigt wird, kann ohne Änderung des Codes substituiert werden, die Tests vereinfacht und verbessert die Entkopplung.
Zum Beispiel, betrachten Sie diesen 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 ist die Umsetzung von PersonService::addManager
und PersonService::removeManager
würde eine Instanz der GroupMembershipService
, um ihre Arbeit zu tun. Ohne Dependency Injection, wäre die traditionelle Art und Weise, dies zu tun einen neuen GroupMembershipService
im Konstruktor von PersonService
zu instanziiert und diese Instanz Attribut in beiden Funktionen verwenden. Wenn jedoch der Konstruktor von GroupMembershipService
mehrere Dinge hat es erfordert, oder schlimmer noch, es gab einige Initialisierung „Setter“, die auf dem GroupMembershipService
genannt zu werden brauchen, wächst der Code ziemlich schnell, und die PersonService
hängt nun nicht nur auf der GroupMembershipService
aber auch alles andere abhängt, dass GroupMembershipService
auf. Darüber hinaus ist die Bindung an GroupMembershipService
in die PersonService
fest einprogrammiert, was bedeutet, dass Sie nicht „dummy up“ eine GroupMembershipService
für Testzwecke oder in verschiedenen Teilen Ihrer Anwendung ein Strategie-Muster zu verwenden.
Mit Dependency Injection, anstatt die GroupMembershipService
in Ihrem PersonService
instanziiert wird, würden Sie entweder übergeben Sie es in die PersonService
Konstruktor, oder aber eine Eigenschaft (Getter und Setter) fügen Sie eine lokale Instanz davon einzustellen. Das bedeutet, dass Ihr PersonService
hat nicht mehr darum zu kümmern, wie ein GroupMembershipService
zu schaffen, ist es akzeptiert nur die, die es gegeben, und arbeitet mit ihnen. Dies bedeutet auch, dass alles, was eine Unterklasse von GroupMembershipService
ist, oder implementiert die GroupMembershipService
Schnittstelle „injiziert“ in die PersonService
werden kann, und die PersonService
braucht sich nicht um die Änderung zu kennen.
Die akzeptierte Antwort ist gut - aber ich würde dazu hinzufügen, dass DI sehr viel ist wie die klassischen von fest codierten Konstanten im Code zu vermeiden.
Wenn Sie eine Konstante wie ein Datenbanknamen verwenden Sie schnell von innen des Codes zu einem gewissen Konfigurationsdatei bewegen würde und eine Variable übergeben diesen Wert an die Stelle enthält, wo es gebraucht wird. Der Grund, das zu tun, ist, dass diese Konstanten in der Regel häufiger ändern als der Rest des Codes. Zum Beispiel, wenn Sie möchten, dass der Code in einer Testdatenbank testen.
ist DI dies in der Welt der objektorientierten Programmierung analog. Die Werte dort statt konstanten Literale sind ganze Objekte - aber der Grund, den Code zu bewegen, sie aus dem Klassencode Erstellen ähnlich ist - die Objekte ändern häufiger dann den Code, der sie verwendet. Ein wichtiger Fall, in dem eine solche Änderung erforderlich ist, ist Tests.
Lassen Sie uns versuchen einfaches Beispiel mit Auto und Motor Klassen, jedes Auto braucht einen Motor überall zu gehen, zumindest vorerst. So unten, wie Code ohne Dependency Injection aussehen wird.
public class Car
{
public Car()
{
GasEngine engine = new GasEngine();
engine.Start();
}
}
public class GasEngine
{
public void Start()
{
Console.WriteLine("I use gas as my fuel!");
}
}
Und die Car-Klasse instanziiert werden wir im nächsten Code verwenden:
Car car = new Car();
Das Problem mit diesem Code, den wir eng mit Gasmotor gekoppelt ist und wenn wir es ElectricityEngine entscheiden zu ändern, dann werden wir brauchen Car-Klasse neu zu schreiben. Und je größer die Anwendung, desto mehr Probleme und Kopfschmerzen müssen wir hinzufügen und neue Art des Motors zu verwenden.
Mit anderen Worten: bei diesem Ansatz ist, dass unsere hohe Car-Klasse ist abhängig von der unteren Ebene Gasmotor-Klasse, die Abhängigkeit Inversion Prinzip verletzt (DIP) aus dem Vollen. DIP legt nahe, dass wir auf Abstraktionen abhängen sollte, nicht konkrete Klassen. So erfüllen diese stellen wir iEngine Schnittstelle und schreiben Code wie folgt:
public interface IEngine
{
void Start();
}
public class GasEngine : IEngine
{
public void Start()
{
Console.WriteLine("I use gas as my fuel!");
}
}
public class ElectricityEngine : IEngine
{
public void Start()
{
Console.WriteLine("I am electrocar");
}
}
public class Car
{
private readonly IEngine _engine;
public Car(IEngine engine)
{
_engine = engine;
}
public void Run()
{
_engine.Start();
}
}
Jetzt ist unsere Car-Klasse ist abhängig von nur der iEngine Schnittstelle, nicht einer spezifischen Implementierung des Motors. Nun ist der einzige Trick, wie wir eine Instanz des Autos schaffen und geben ihm eine tatsächliche Betonmaschinen-Klasse wie Gasmotor oder ElectricityEngine. Das ist, wo Dependency Injection kommt in.
Car gasCar = new Car(new GasEngine());
gasCar.Run();
Car electroCar = new Car(new ElectricityEngine());
electroCar.Run();
Hier im Grunde injizieren wir (pass) unsere Abhängigkeit (Engine-Instanz) auf Auto-Konstruktor. So, jetzt unsere Klassen haben lose Kopplung zwischen Objekten und den Abhängigkeiten, und wir können auf einfache Weise neue Arten von Motoren hinzufügen, ohne die Car-Klasse zu ändern.
Der Hauptvorteil der Dependency Injection , dass Klassen sind mehr lose gekoppelt sind, weil sie nicht hart codierte Abhängigkeiten. Dies folgt der Dependency Inversion Principle, die oben erwähnt wurde. Stattdessen spezifische Implementierungen der Referenzierung, fordern Klassen Abstraktionen (in der Regel Schnittstellen ), die sie zur Verfügung gestellt werden, wenn die Klasse aufgebaut ist.
Also am Ende Dependency Injection ist nur eine Technik für Erreichen lose Kopplung zwischen Objekten und deren Abhängigkeiten. Anstatt direkt Abhängigkeiten instanziieren, die Klasse muss in bestellen ihre Aktionen auszuführen, Abhängigkeiten werden in die Klasse zur Verfügung gestellt (Meist) über Konstruktor Injektion.
Auch wenn wir viele Abhängigkeiten haben, ist es eine sehr gute Übung Inversion of Control (IoC) Behälter zu verwenden, die wir sagen können, welche Schnittstellen abgebildet werden sollten, um die konkrete Implementierungen für alle unsere Abhängigkeiten und wir können es diese Abhängigkeiten für uns lösen wenn es baut unser Objekt. Zum Beispiel könnten wir in der Zuordnung für die IoC-Container angeben, die die iEngine Abhängigkeit sollte auf die Gasmotor Klasse zugeordnet werden und wenn wir fragen die IoC-Container für eine Instanz unseres Auto Klasse, es wird unsere automatisch konstruiert Auto Klasse mit einer Gasmotor Abhängigkeit eingeleitet.
UPDATE: Beobachtete Kurs über EF-Core von Julie Lerman vor kurzem und auch mochte sie kurze Definition über DI
.Dependency Injection ist ein Muster, Ihre Anwendung zu ermöglichen, zu injizieren Objekte on the fly zu Klassen, die sie benötigen, ohne diejenigen zu zwingen Klassen für diese Objekte verantwortlich sein. Es ermöglicht Ihren Code zu sein mehr lose gekoppelt und Entity Framework Kernstopfen in diesem gleichen Service-System.
Nehmen wir an, Sie wollen angeln gehen:
-
Ohne Dependency Injection, müssen Sie die Pflege selbst von allem zu nehmen. Sie benötigen ein Boot zu finden, die eine Angelrute zu kaufen, für Köder zu suchen, etc. Es ist natürlich möglich, aber es bringt eine Menge Verantwortung auf Ihnen. In Software ausgedrückt bedeutet dies, dass Sie einen Lookup für all diese Dinge zu vollbringen haben.
-
Mit Dependency Injection, jemand anderes nimmt kümmert sich um alle die Vorbereitung und macht die erforderliche Ausrüstung zur Verfügung. Sie erhalten das Boot ( „injiziert werden“), die Angel und den Köder -. Alle einsatzbereit
Diese ist die einfachste Erklärung über Dependency Injection und Dependency Injection Container ich je gesehen habe:
Ohne Injection Dependency
- Anwendung benötigt Foo (beispielsweise ein Controller), so:
- Anwendung erstellt Foo
- Anwendung ruft Foo
- Foo braucht Bar (zum Beispiel ein Dienst), so:
- Foo schafft Bar
- Foo Anrufe Bar
- Bar braucht Bim (ein Service, ein Repository, ...), so:
- Bar schafft Bim
- Bar etwas tut,
Mit Dependency Injection
- Anwendung benötigt Foo, die Bar braucht, die Bim benötigt, so:
- Anwendung erstellt Bim
- Anwendung schafft Bar und gibt es Bim
- Anwendung erstellt Foo und gibt es Bar
- Anwendung ruft Foo
- Foo Anrufe Bar
- Bar etwas tut,
- Foo Anrufe Bar
Mit einer Dependency Injection Container
- Anwendung muss Foo so:
- Anwendung wird Foo vom Behälter, so:
- Container erstellt Bim
- Container schafft Bar und gibt es Bim
- Container schafft Foo und gibt es Bar
- Anwendung ruft Foo
- Foo Anrufe Bar
- Bar etwas tut,
- Foo Anrufe Bar
Dependency Injection und Dependency Injection Container sind verschiedene Dinge:
- Dependency Injection ist ein Verfahren zum Schreiben von Code besser
- a DI Container ist ein Werkzeug, um Abhängigkeiten Injektion
Sie brauchen keine Behälter Dependency Injection zu tun. Jedoch ein Behälter kann Ihnen helfen.
nicht „Dependency Injection“ nur bedeuten, parametrisierte Konstrukteure und öffentliche Setter mit
James Shore Artikel zeigt die folgenden Beispiele zum Vergleich .
Constructor ohne Dependency Injection:
public class Example {
private DatabaseThingie myDatabase;
public Example() {
myDatabase = new DatabaseThingie();
}
public void doStuff() {
...
myDatabase.getData();
...
}
}
Constructor mit Dependency Injection:
public class Example {
private DatabaseThingie myDatabase;
public Example(DatabaseThingie useThisDatabaseInstead) {
myDatabase = useThisDatabaseInstead;
}
public void doStuff() {
...
myDatabase.getData();
...
}
}
Was ist Dependency Injection (DI)?
Wie andere gesagt haben, Dependency Injection (DI) entfernt die Verantwortung der direkten Erstellung und Verwaltung der Lebensdauer von anderen Objektinstanzen, auf denen unsere Klasse von Interesse (Consumer-Klasse) abhängig ist ( in der UML Sinn ). Diese Instanzen werden stattdessen an unsere Verbraucher-Klasse übergeben, in der Regel als Konstruktorparameter oder über Eigentum Setter (die Verwaltung des Abhängigkeitsobjekt Instancing und vorbei an den Verbraucher-Klasse wird in der Regel durchgeführt, indem ein Inversion of Control (IoC) Behälter, aber das ist ein anderes Thema).
DI, DIP und SOLID
Insbesondere im Paradigma von Robert C Martin SOLID Prinzipien der Objektgestaltung Oriented ist DI
eine der möglichen Implementierungen des Dependency Inversion Principle (DIP) . Der DIP ist die D
des SOLID
Mantra -. Andere DIP-Implementierungen umfassen den Service Locator und Plugin-Muster
Das Ziel der DIP ist eng, konkrete Abhängigkeiten zwischen den Klassen zu entkoppeln und stattdessen die Kopplung mittels einer Abstraktion zu lösen, die über ein interface
, abstract class
oder pure virtual class
erreicht werden können, abhängig von der Sprache und Ansatz .
Ohne den DIP, unser Code (ich habe diese ‚raubend Klasse‘ genannt) direkt auf eine konkrete Abhängigkeit gekoppelt ist und auch belastet wird oft mit der Verantwortung zu wissen, wie, zu erhalten und zu verwalten, eine Instanz dieser Abhängigkeit, dh vom Konzept her:
"I need to create/use a Foo and invoke method `GetBar()`"
Während nach dem Aufbringen der DIP wird die Anforderung gelockert, und die Sorge der Beschaffung und Verwaltung der Lebensdauer der Foo
Abhängigkeit wird entfernt:
"I need to invoke something which offers `GetBar()`"
Verwendung DIP (und DI)?
Entkoppelung Abhängigkeiten zwischen den Klassen auf diese Weise ermöglicht einfache Substitution diese Abhängigkeitsklassen mit anderen Implementierungen, die auch die Voraussetzungen der Abstraktion erfüllen (zB die Abhängigkeit kann mit einer weiteren Implementierung der gleichen Schnittstelle geschaltet werden ). Außerdem ist, wie andere schon erwähnt haben, möglicherweise die häufigste Grund Klassen über den DIP zu entkoppeln ist eine verzehr Klasse zu ermöglichen, in Isolation getestet werden, da diese gleichen Abhängigkeiten jetzt stubbed werden können und / oder verspottet.
Eine Folge von DI ist, dass die Lebensdauer Management von Abhängigkeitsobjektinstanzen wird nicht mehr durch eine verzehr Klasse gesteuert, wie das Abhängigkeitsobjekt nun in die verzehr Klasse (über Konstruktor oder Setter-Injektion) übergeben wird.
Dies kann auf unterschiedliche Weise betrachtet werden:
-
eine (abstrakte) Fabrik durch die Injektion für die Erstellung der Abhängigkeit von Klasseninstanzen in die Consumer-Klasse
- Wenn Lebensdauer Kontrolle der Abhängigkeiten von der verzehr Klasse beibehalten werden muss, kann die Kontrolle wieder hergestellt werden. Der Verbraucher wird in der Lage seine Instanzen auf dem Werk über eine
Create
zu erhalten, wie erforderlich, und entsorgen diese Fälle einmal abgeschlossen. - Oder Lebensdauer Kontrolle von Abhängigkeits Fällen kann auf einen IoC-Container (mehr dazu weiter unten) aufgegeben werden.
Wenn DI benutzen?
- Wo wird es wahrscheinlich eine Notwendigkeit, eine Abhängigkeit für eine gleichwertige Umsetzung zu ersetzen,
- Jedes Mal, wo Sie Einheit testen Sie die Methoden einer Klasse in Isolation seiner Abhängigkeiten benötigt,
- Wo Unsicherheit der Lebensdauer eines Abhängigkeits Experimente rechtfertigen können (beispielsweise He,
MyDepClass
ist Thread-sicher - was ist, wenn wir es ein Singletonund injizieren die gleiche Instanz in alle Verbraucher?)
Beispiel:
Hier ist eine einfache C # -Implementierung. In Anbetracht der unter Verbrauchen Klasse:
public class MyLogger
{
public void LogRecord(string somethingToLog)
{
Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
}
}
Obwohl scheinbar harmlos, es zwei static
Abhängigkeiten von zwei anderen Klassen hat, System.DateTime
und System.Console
, die nicht nur die Logging-Ausgabeoptionen begrenzen (Anmeldung wird auf der Konsole wertlos, wenn niemand zusieht), aber schlimmer ist, ist es schwierig, automatisch die Abhängigkeit von einem nicht-deterministischen Systemtakt gegeben Test.
Wir können jedoch DIP
zu dieser Klasse gelten, durch die die Sorge der timestamping als Abhängigkeit abstrahieren und Kopplung MyLogger
nur auf eine einfache Schnittstelle:
public interface IClock
{
DateTime Now { get; }
}
Wir können auch die Abhängigkeit von Console
zu einer Abstraktion, wie ein TextWriter
lösen. Abhängigkeitsinjektion wird üblicherweise als Injektion entweder constructor
(vorbei eine Abstraktion zu einer Abhängigkeit als Parameter an dem Konstruktor einer verzehr Klasse) oder Setter Injection
(vorbei, die die Abhängigkeit über einen setXyz()
setter oder eine NET-Eigenschaft mit {set;}
definiert) umgesetzt. Constructor Injektion wird bevorzugt, da dies garantiert die Klasse in einem korrekten Zustand nach dem Bau sein wird, und ermöglicht es, die internen Abhängigkeitsfelder als readonly
(C #) oder final
(Java) markiert werden. Also mit Konstruktor Injektion auf dem obigen Beispiel das läßt uns mit:
public class MyLogger : ILogger // Others will depend on our logger.
{
private readonly TextWriter _output;
private readonly IClock _clock;
// Dependencies are injected through the constructor
public MyLogger(TextWriter stream, IClock clock)
{
_output = stream;
_clock = clock;
}
public void LogRecord(string somethingToLog)
{
// We can now use our dependencies through the abstraction
// and without knowledge of the lifespans of the dependencies
_output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
}
}
(Ein konkretes Clock
muss zur Verfügung gestellt werden, DateTime.Now
was natürlich zurückkehren konnte, und die beiden Abhängigkeiten müssen durch einen IoC-Container über Konstruktor Injektion zur Verfügung gestellt werden)
Eine automatisierte Unit Test kann gebaut werden, die endgültig beweist, dass unsere Logger korrekt funktioniert, wie wir jetzt die Kontrolle über die Abhängigkeiten - die Zeit, und wir können auf die schriftliche Ausgabe auszuspionieren:
[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
// Arrange
var mockClock = new Mock<IClock>();
mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
var fakeConsole = new StringWriter();
// Act
new MyLogger(fakeConsole, mockClock.Object)
.LogRecord("Foo");
// Assert
Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}
Next Steps
Dependency Einspritzung wird immer im Zusammenhang mit einem Invertierung des Kontrollbehälters (IOC) , (einzuzuspritzen zur Verfügung stellt) die konkrete Abhängigkeit Instanzen und Lebensdauer Instanzen zu verwalten. Bei der Konfiguration / Bootstrapping Prozess, ermöglichen IoC
Behälter folgenden definiert werden:
- Abbildung zwischen jeder Abstraktion und der konfigurierten konkreten Implementierung (z.B. "Jedesmal, wenn ein Verbraucher einem
IBar
anfordert, gibt einConcreteBar
instance" ) - Politik kann für die Lebensdauer-Management jeder Abhängigkeit aufgebaut werden, z.B. ein neues Objekt für jeden Verbraucher Instanz zu schaffen, für alle Verbraucher, ein Singleton Abhängigkeits Beispiel zu teilen die gleiche Abhängigkeit Instanz nur über den gleichen Thread, etc. zu teilen.
- In .Net, IoC Container sind uns bewusst, Protokolle wie
IDisposable
und wird auf die Verantwortung derDisposing
Abhängigkeiten im Einklang mit der projektierten Lebensdauer-Management übernehmen.
Normalerweise einmal IoC Container konfiguriert wurden / Bootstrap arbeiten sie nahtlos in den Hintergrund so dass der Kodierer auf dem Code zur Hand konzentrieren, anstatt sich Gedanken über Abhängigkeiten.
Der Schlüssel zum DI-Kommandocode ist statische Kopplung von Klassen zu vermeiden, und nicht neu () zu verwenden, für die Schaffung von Abhängigkeiten
Wie pro obigem Beispiel Entkopplung von Abhängigkeiten hat einigen konstruktiven Aufwand erfordern, und für den Entwickler, gibt es einen Paradigmenwechsel notwendig, um die Gewohnheit zu brechen von Abhängigkeiten direkt new
ing und stattdessen Vertrauen auf die Container Abhängigkeiten zu verwalten.
Aber die Vorteile sind viele, vor allem in der Fähigkeit, gründlich Ihre Klasse von Interesse zu testen.
Hinweis : Die Erstellung / Kartierungs- / Projektion (via new ..()
) von POCO / POJO / Serialisierung DTOs / Entity Graphs / Anonymous JSON Projektionen et al - dh „Daten nur“ Klassen oder Aufzeichnungen - verwendet oder von Methoden zurückgegeben werden nicht gilt als Abhängigkeiten (im UML-Sinn) und nicht Gegenstand DI. Mit new
zu projizieren diese ist nur in Ordnung.
Um Dependency Injection-Konzept einfach zu verstehen zu machen. Nehmen wir ein Beispiel von Schaltknopf, um umzuschalten (on / off), um eine Glühbirne.
Ohne Injection Dependency
Schalter muss vorher wissen, welche Lampe ich verbunden bin zu (hartcodierte Abhängigkeit). Also,
Schalter -> PermanentBulb // Schalter direkt an permanent Lampe angeschlossen ist, die Prüfung nicht möglich, einfach
Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}
Mit Dependency Injection
Schalter nur weiß, ich muß Ein- / Ausschalten je nachdem, welche Glühlampe ist mir übergeben. Also,
Schalter -> Bulb1 OR Bulb2 OR NightBulb (injiziert Abhängigkeit)
Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}
Ändern James Beispiel für Schalter und Leuchtmittel:
public class SwitchTest {
TestToggleBulb() {
MockBulb mockbulb = new MockBulb();
// MockBulb is a subclass of Bulb, so we can
// "inject" it here:
Switch switch = new Switch(mockBulb);
switch.ToggleBulb();
mockBulb.AssertToggleWasCalled();
}
}
public class Switch {
private Bulb myBulb;
public Switch() {
myBulb = new Bulb();
}
public Switch(Bulb useThisBulbInstead) {
myBulb = useThisBulbInstead;
}
public void ToggleBulb() {
...
myBulb.Toggle();
...
}
}`
Der ganze Sinn der Dependency Injection (DI) ist Quellcode der Anwendung zu halten clean und stabil :
- clean der Abhängigkeit Initialisierungscode
- stabil , unabhängig von Abhängigkeit verwendet
Praktisch trennt jedes Designmuster betrifft künftige Änderungen betreffen Mindest-Dateien zu machen.
Die spezifische Domäne von DI ist eine Delegation der Abhängigkeit Konfiguration und Initialisierung.
Beispiel: DI mit Shell-Skript
Wenn Sie gelegentlich außerhalb von Java arbeiten, daran erinnern, wie source
oft in vielen Skriptsprachen verwendet wird (Shell, Tcl, etc. oder sogar import
in Python zu diesem Zweck missbraucht).
Betrachten Sie einfach dependent.sh
Skript:
#!/bin/sh
# Dependent
touch "one.txt" "two.txt"
archive_files "one.txt" "two.txt"
Das Skript ist abhängig. Es erfolgreich nicht selbst ausführen wird (archive_files
nicht definiert ist)
Sie definieren archive_files
in archive_files_zip.sh
Implementierung Skript (mit zip
in diesem Fall):
#!/bin/sh
# Dependency
function archive_files {
zip files.zip "$@"
}
Statt source
-ing Implementierung Skript direkt in den abhängigen ein, erhalten Sie einen injector.sh
"Container" verwendet werden, die beide "Komponenten" Wraps:
#!/bin/sh
# Injector
source ./archive_files_zip.sh
source ./dependent.sh
Die archive_files
Abhängigkeit hat gerade gewesen injiziert in abhängig Skript.
Sie injiziert haben könnte Abhängigkeit, die archive_files
mit tar
oder xz
implementiert.
Beispiel: Entfernen DI
Wenn dependent.sh
Skript verwendet Abhängigkeiten direkt, würde der Ansatz genannt werden Abhängigkeits Lookup (die entgegengesetzt ist Dependency Injection ):
#!/bin/sh
# Dependent
# dependency look-up
source ./archive_files_zip.sh
touch "one.txt" "two.txt"
archive_files "one.txt" "two.txt"
Das Problem ist jetzt, dass abhängige „Komponente“ Initialisierung selbst ausführen muss.
Die „Komponente“ ‚s Quellcode ist weder clean noch stabil , da alle Änderungen in der Initialisierung von Abhängigkeiten erfordern neue Version für‚Komponenten‘‘ s Quellcodedatei als gut.
Letzte Worte
DI ist nicht so groß hervorgehoben und wie in Java-Frameworks populär gemacht.
Aber es ist ein allgemeiner Ansatz aufzuspalten Anliegen:
- Anwendung Entwicklung ( einzig Quellcode Release Lifecycle)
- Anwendung Einsatz ( mehr Zielumgebungen mit unabhängigen Lifecycles)
Die Konfiguration mit nur mit Abhängigkeits Lookup hilft nicht, wie Anzahl der Konfigurationsparameter pro Abhängigkeit ändern kann (zB neuer Authentifizierungstyp) sowie Anzahl der unterstützten Arten von Abhängigkeiten (zB neuer Datenbanktyp).
Alle oben genannten Antworten sind gut, mein Ziel ist es, das Konzept auf einfache Art und Weise zu erklären, so dass jeder kann ohne Programmierkenntnisse auch Konzept verstehen
Dependency Injection ist eine der Design-Muster, das es uns, komplexe Systeme auf einfachere Art und Weise erstellen helfen.
Wir können eine Vielzahl von Anwendung dieses Muster in unserem täglichen Leben sehen. Einige der Beispiele sind Kassettenrecorder, VCD, CD-Laufwerk, etc.
Das oben gezeigte Bild ist ein Bild von Reel-to-Reel tragbaren Tonbandgerät, Mitte des 20. Jahrhunderts. Quelle .
Die primäre Absicht einer Bandaufzeichnungsmaschine oder Wiedergabe Ton aufzunehmen.
ein System Beim Entwerfen sie eine Rolle benötigen oder die Wiedergabe von Sound oder Musik aufzuzeichnen. Es gibt zwei Möglichkeiten für die Gestaltung dieses Systems
- können wir die Spule im Inneren der Maschine platzieren
- wir einen Haken für die Spule zur Verfügung stellen kann, wo sie platziert werden können.
Wenn wir verwenden, um das erste, das wir brauchen, um die Maschine zu öffnen, um die Rolle zu ändern. wenn wir für die zweite entscheiden, die einen Haken für Haspel platzieren, werden wir einen zusätzlichen Vorteil spielen keine Musik immer von den Rollenwechsel. und auch die Funktion nur zur Verringerung was auch immer in der Rolle zu spielen.
Wie weise Dependency Injection ist der Prozess, die Abhängigkeiten der Externalisierung nur auf der spezifischen Funktionalität der Komponente zu konzentrieren, so dass unabhängige Komponenten miteinander gekoppelt werden können, ein komplexes System zu bilden.
Die wichtigsten Vorteile, die wir durch die Verwendung Dependency Injection erreicht.
- Hohe Kohäsion und lose Kopplung.
- Externalisierende Abhängigkeit und sucht nur auf Verantwortung.
- Die Dinge als Komponenten und zu kombinieren, um ein großen Systeme mit hohen Fähigkeiten zu bilden.
- Es hilft qualitativ hochwertige Komponenten zu entwickeln, da sie unabhängig voneinander entwickelt werden sie richtig getestet werden.
- Es hilft, die Komponente durch eine andere zu ersetzen, wenn einer ausfällt.
Nun ist dieses Konzept wird einen Tag bildet die Grundlage des bekannten Frameworks in der Programmierung Welt. Der Frühling Angular etc ist das bekannte Software-Frameworks auf der Oberseite dieses Konzeptes gebaut
Dependency Injection ist ein Muster verwendete Instanzen von Objekten zu erstellen, die anderen Objekte verlassen sich auf, ohne bei der Kompilierung zu wissen, welche Klasse verwendet werden soll, dass die Funktionalität zu erweitern oder einfach die Art und Weise Eigenschaften zu einem Objekt der Injektion wird Dependency Injection genannt.
Beispiel für Dependency Injection
Bisher schreiben wir Code wie folgt
Public MyClass{
DependentClass dependentObject
/*
At somewhere in our code we need to instantiate
the object with new operator inorder to use it or perform some method.
*/
dependentObject= new DependentClass();
dependentObject.someMethod();
}
Mit Dependency Injection, die Abhängigkeit Injektor wird die Instanziierung für uns ausziehen
Public MyClass{
/* Dependency injector will instantiate object*/
DependentClass dependentObject
/*
At somewhere in our code we perform some method.
The process of instantiation will be handled by the dependency injector
*/
dependentObject.someMethod();
}
Sie können auch lesen
Unterschied zwischen Inversion of Control & Dependency Injection
Was ist Dependency Injection?
Dependency Injection (DI) bedeutet, um die Objekte zu entkoppeln, die voneinander abhängig sind. Sagt Objekt A auf B Objekt abhängig ist, so dass die Idee, diese Aufgabe voneinander zu entkoppeln, ist. Wir brauchen nicht zu hart Code das Objekt Schlüsselwort new eher Abhängigkeiten Objekte zur Laufzeit trotz der Kompilierung zu teilen. Wenn wir darüber sprechen,
Wie Dependency Injection Werke im Frühjahr:
Wir brauchen nicht zu hart Code das Objekt Schlüsselwort new eher die Bean-Abhängigkeit in der Konfigurationsdatei definieren. Die Federbehälter für Einhaken alle verantwortlich sein.
Inversion of Control (IOC)
IOC ist ein allgemeines Konzept, und es kann auf viele verschiedene Arten und Dependency Injection ist ein konkretes Beispiel für IOC ausgedrückt werden.
Zwei Arten von Dependency Injection:
- Constructor Injection
- Setter Injection
1. Constructor-basierte Dependency Injection:
Constructor basierten DI wird erreicht, wenn der Behälter eine Klassenkonstruktors mit einer Anzahl von Argumenten aufruft, die jeweils eine Abhängigkeit von anderen Klasse repräsentiert.
public class Triangle {
private String type;
public String getType(){
return type;
}
public Triangle(String type){ //constructor injection
this.type=type;
}
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
<constructor-arg value="20"/>
</bean>
2. Setter-basierte Dependency Injection:
Setter-basierte DI durch die Container rufenden Setter-Methoden auf Ihren Bohnen erfolgt nach dem Aufruf einen Konstruktor ohne Argumente oder No-Argument statische Factory-Methode Bean zu instanziiert.
public class Triangle{
private String type;
public String getType(){
return type;
}
public void setType(String type){ //setter injection
this.type = type;
}
}
<!-- setter injection -->
<bean id="triangle" class="com.test.dependencyInjection.Triangle">
<property name="type" value="equivialteral"/>
Hinweis: Es ist eine gute Daumenregel zu Konstruktorargumente für verbindliche Abhängigkeiten und Setter für optionale Abhängigkeiten zu verwenden. Beachten Sie, dass die, wenn wir verwenden Annotation basiert als @Required Anmerkung auf einem Einrichter kann verwendet werden, Setter als erforderlichen Abhängigkeiten zu machen.
Die beste Analogie, die ich denken kann, ist der Chirurg und sein Assistent (en) in einem Operationssaal, wo der Chirurg die Hauptperson und sein Assistent ist, die die verschiedenen chirurgischen Komponenten bereitstellt, wenn er es braucht, so dass der Chirurg konzentrieren auf die eine Sache tut er am besten (Chirurgie). Ohne den Assistenten hat der Chirurg sich die Komponenten jedes Mal zu bekommen, die er braucht.
DI kurz, ist eine Technik, eine gemeinsame zusätzliche Verantwortung (Last) auf Komponenten zu entfernen, die abhängigen Komponenten zu holen, indem sie es bereitstellt.
DI bringt Sie näher an der einzigen Verantwortung (SR) Prinzip, wie die surgeon who can concentrate on surgery
.
Wenn DI verwenden: Ich würde empfehlen, mit DI in fast allen Produktionsprojekten (klein / groß), insbesondere in Umgebungen immer ändernden Geschäfts:)
Warum: Weil Sie Ihren Code leicht prüfbar, mockable usw. sein, so dass Sie schnell Ihre Änderungen testen und auf den Markt drängen. Außerdem, warum würden Sie nicht, wenn Sie es gibt viele genial kostenlose Tools / Frameworks Sie auf Ihrer Reise zu einer Code-Basis zu unterstützen, wo Sie mehr Kontrolle haben.
Es bedeutet, dass Objekte sollten nur so viele Abhängigkeiten, wie benötigt wird, um ihre Arbeit zu tun, und die Abhängigkeiten sollen einige sein. Darüber hinaus sollte ein Objekt der Abhängigkeiten von Schnittstellen und nicht auf „Beton“ Objekte, wenn möglich. (Ein konkretes Objekt ist jedes Objekt mit dem Schlüsselwort neu erstellt.) Los Kopplung größer Wiederverwertbarkeit fördert, einfacher Wartbarkeit und ermöglicht es Ihnen, leicht zu schaffen „Mock“ Objekte anstelle von teueren Dienstleistungen.
Die „Dependency Injection“ (DI) wird auch als „Inversion of Control“ (IOC) bekannt ist, kann für die Förderung dieser lose Kopplung als eine Technik verwendet werden.
Es gibt zwei primäre Ansätze zur Umsetzung von DI:
- Constructor Injektion
- Setter Injektion
Constructor Injektion
Es ist die Technik des Führens Objekte Abhängigkeiten an den Konstruktor.
Beachten Sie, dass der Konstruktor eine Schnittstelle akzeptiert und keine konkreten Objekt. Beachten Sie auch, dass eine Ausnahme ausgelöst wird, wenn der orderDao Parameter null ist. Dies unterstreicht die Bedeutung eine gültige Abhängigkeit zu empfangen. Constructor Injection ist, meiner Meinung nach, der bevorzugten Mechanismus zum Einstellen eines Objekt seiner Abhängigkeiten. Es ist klar, in den Entwickler, während das Objekt aufrufen, die Abhängigkeiten müssen für die ordnungsgemäße Ausführung der „Person“ Objekt gegeben werden.
Setter Injection
Aber das folgende Beispiel betrachtet ... Angenommen, Sie eine Klasse mit zehn Methoden, die keine Abhängigkeiten haben, aber Sie sind das Hinzufügen eine neue Methode, die eine Abhängigkeit von IDao hat. Sie könnten den Konstruktor ändern Konstruktor Injection zu verwenden, aber dies kann man zu Änderungen zwingen, alle Konstruktor der ganzen Ort aufruft. Alternativ können Sie einfach einen neuen Konstruktor hinzufügen, die die Abhängigkeit nimmt, dann aber wie weiß ein Entwickler leicht, wenn ein Konstruktor über den anderen zu verwenden. Schließlich, wenn die Abhängigkeit ist sehr teuer zu schaffen, warum soll es an den Konstruktor erstellt und weitergegeben werden, wenn es nur selten verwendet werden kann? „Setter Injection“ ist eine andere DI-Technik, die in Situationen wie diese verwendet werden kann.
Setter Injection nicht zwingen Abhängigkeiten an den Konstruktor übergeben werden. Stattdessen werden die Abhängigkeiten auf öffentliche Eigenschaften durch das Objekt in der Notwendigkeit ausgesetzt gesetzt. Wie bereits angedeutet, sind die primären Motivatoren für dies zu tun:
- Unterstützung Dependency Injection, ohne den Konstruktor einer Legacy-Klasse ändern zu müssen.
- teure Ressourcen oder Dienste erlaubt so spät wie möglich geschaffen werden, und nur bei Bedarf.
ist das Beispiel dafür, wie der obige Code aussehen würde:
public class Person {
public Person() {}
public IDAO Address {
set { addressdao = value; }
get {
if (addressdao == null)
throw new MemberAccessException("addressdao" +
" has not been initialized");
return addressdao;
}
}
public Address GetAddress() {
// ... code that uses the addressdao object
// to fetch address details from the datasource ...
}
// Should not be called directly;
// use the public property instead
private IDAO addressdao;
Beispiel, haben wir 2 Klasse Client
und Service
. Client
wird verwenden Service
public class Service {
public void doSomeThingInService() {
// ...
}
}
Ohne Injection Dependency
Way 1)
public class Client {
public void doSomeThingInClient() {
Service service = new Service();
service.doSomeThingInService();
}
}
Way 2)
public class Client {
Service service = new Service();
public void doSomeThingInClient() {
service.doSomeThingInService();
}
}
Way 3)
public class Client {
Service service;
public Client() {
service = new Service();
}
public void doSomeThingInClient() {
service.doSomeThingInService();
}
}
1) 2) 3) Mit
Client client = new Client();
client.doSomeThingInService();
Vorteile
- Einfache
Nachteile
- Hard für Test
Client
Klasse - Wenn wir
Service
Konstruktor zu ändern, müssen wir Code in jedem Ort erstellenService
Objekt ändern
Verwendung Dependency Injection
Way 1) Constructor Injektion
public class Client {
Service service;
Client(Service service) {
this.service = service;
}
// Example Client has 2 dependency
// Client(Service service, IDatabas database) {
// this.service = service;
// this.database = database;
// }
public void doSomeThingInClient() {
service.doSomeThingInService();
}
}
mit
Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();
Way 2) Setter Injektion
public class Client {
Service service;
public void setService(Service service) {
this.service = service;
}
public void doSomeThingInClient() {
service.doSomeThingInService();
}
}
mit
Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();
Way 3) Schnittstelle Injektion
Überprüfen Sie https://en.wikipedia.org/wiki/Dependency_injection
===
Nun wird dieser Code bereits folgen Dependency Injection
und es ist einfacher für Test Client
Klasse.
Allerdings verwenden wir noch new Service()
viele Zeit, und es ist nicht gut, wenn Änderung Service
Konstruktor. Um dies zu verhindern, können wir DI Injektor wie
verwenden
1) Einfache manuelle Injector
public class Injector {
public static Service provideService(){
return new Service();
}
public static IDatabase provideDatatBase(){
return new SqliteDatabase();
}
public static ObjectA provideObjectA(){
return new ObjectA(provideService(...));
}
}
Mit
Service service = Injector.provideService();
2) Verwenden Sie Bibliothek: Für Android dagger2
Vorteile
- Stellen Test einfacher
- Wenn Sie die
Service
zu ändern, müssen Sie es nur in Injector Klasse ändern - Wenn Sie
Constructor Injection
verwenden, wenn Sie auf KonstruktorClient
betrachten, werden Sie, wie viele Abhängigkeit vonClient
-Klasse
Nachteile
- Wenn Sie
Constructor Injection
verwenden, dasService
Objekt erstellt wird, wennClient
erstellt, einmal verwenden wir die Funktion inClient
Klasse ohne VerwendungService
so erstelltService
verschwendet
Dependency Injection Definition
https://en.wikipedia.org/wiki/Dependency_injection
Eine Abhängigkeit ist ein Objekt, das verwendet werden kann (
Service
)
Eine Injektion ist die Verabschiedung einer Abhängigkeit (Service
) zu einem abhängigen Objekt (Client
), die es verwenden würden
Ich denke, da jeder für DI geschrieben hat, lassen Sie mich ein paar Fragen stellen ..
- Wenn Sie eine Konfiguration von DI haben, wo alle tatsächlichen Implementierungen (nicht-Schnittstellen), die (mit einer Steuerung für beispiel Dienste) in eine Klasse eingespritzt werden werden, warum ist das nicht eine Art von Hartcodierung?
- Was passiert, wenn ich das Objekt zur Laufzeit geändert werden soll? Zum Beispiel meine Config schon sagt, wenn ich MyController instanziiert, für Filelogger als ILogger injizieren. Aber ich könnte wollen DatabaseLogger injizieren.
- Jedesmal, wenn ich ändern wollen, was meine Objekte AClass braucht, muss ich jetzt in zwei Plätze suchen - Die Klasse selbst und die Konfigurationsdatei. Wie funktioniert das Leben leichter machen?
- Wenn Aproperty von AClass nicht eingespritzt wird, ist es schwieriger, es zu verspotten?
- Gehen wir zurück auf die erste Frage. Bei der Verwendung von neuem Objekt () schlecht ist, wie kommen wir die Umsetzung und nicht die Schnittstelle zu injizieren? Ich glaube, dass viele von euch sagen wir in der Tat sind die Schnittstelle Injektion aber die Konfiguration macht die Implementierung dieser Schnittstelle angeben ..not zur Laufzeit .. es während der Kompilierung fest einprogrammiert ist.
Dies basiert auf der Antwort @ Adam N geschrieben.
Warum PersonService müssen nicht mehr über GroupMembershipService Sorgen machen? Sie erwähnten eben GroupMembership mehrere Dinge (Objekte / Objekte) hat es hängt davon ab. Wenn GMService in PService erforderlich war, würden Sie es als eine Eigenschaft haben. Sie können, dass verspotten, unabhängig davon, ob Sie es injiziert oder nicht. Das einzige Mal, Ich mag würde es injiziert werden soll, wenn GMService spezifischere Kind Klassen hatte, die man nicht erst zur Laufzeit kennen würde. Dann würden Sie die Unterklasse injizieren. Oder, wenn man will, dass entweder als Singleton oder Prototypen verwenden. Um ehrlich zu sein, hat die Konfigurationsdatei alles fest einprogrammiert, so weit wie das, was Unterklasse für einen Typen (Interface) es wird während der Kompilierung injizieren.
Bearbeiten
Ein schöner Kommentar von Jose Maria Arranz auf DI
erhöht DI Zusammenhalt durch die Notwendigkeit entfällt, die Richtung der Abhängigkeit und schreiben Sie einen beliebigen Glue-Code zu bestimmen.
Falsch. Die Richtung der Abhängigkeiten ist in XML-Form oder als Anmerkungen, Ihre Abhängigkeiten als XML-Code und Anmerkungen geschrieben. XML und Anmerkungen sind Quellcode.
reduziert DI Kopplung durch alle Komponenten modular (das heißt replacable) machen und haben klar definierte Schnittstellen miteinander.
Falsch. Sie brauchen keinen DI Rahmen benötigen einen modularen Code basierend auf Schnittstellen zu bauen.
Über ersetzbar: mit einem sehr einfachen .properties archivieren und Class.forName Sie definieren können, wich Klassen ändern können. Wenn jede Klasse des Codes geändert werden kann, ist Java nicht für Sie, eine Skriptsprache verwenden. Durch die Art und Weise: Anmerkungen können nicht ohne erneute Kompilierung geändert werden
.Meiner Meinung nach ist es eine einzige Grund für die DI-Frameworks: Kesselblech Reduktion. Mit einem gut gemacht Fabriksystem können Sie das gleiche tun, kontrollierter und vorhersagbarer als bevorzugte DI Rahmen, Rahmen DI Versprechen Code Reduktion (XML und Anmerkungen Quellcode sind auch). Das Problem ist, diese Kessel Platte Reduktion in sehr sehr einfachen Fällen nur real ist (eine Instanz pro Klasse und ähnliche), manchmal in der realen Welt das eigneten Dienstobjekt Kommissionierung als Abbildung eine Klasse auf ein Singleton-Objekt nicht so einfach ist.
Dependency Injection eine Art und Weise bedeutet (eigentlich any-Weg ) für einen Teil des Codes (zB eine Klasse) hat Zugriff auf Abhängigkeiten (andere Teile des Codes, zB andere Klassen, es hängt davon ab,) in einer modularen Art und Weise, ohne sie fest einprogrammiert werden (so können sie frei werden, ändern oder außer Kraft gesetzt oder sogar zu einem anderen Zeitpunkt geladen werden, je nach Bedarf)
(und ps, ja es ein übermäßig gehypten 25 $ name für ein ziemlich einfaches, Konzept worden ist) , mein .25
Cent
Ich weiß, es gibt bereits viele Antworten, aber ich fand das sehr hilfreich: http: //tutorials.jenkov. com / dependency-Injektion / index.html
Keine Abhängigkeit:
public class MyDao {
protected DataSource dataSource =
new DataSourceImpl("driver", "url", "user", "password");
//data access methods...
public Person readPerson(int primaryKey) {...}
}
Abhängigkeit:
public class MyDao {
protected DataSource dataSource = null;
public MyDao(String driver, String url, String user, String
password){
this.dataSource = new DataSourceImpl(driver, url, user, password);
}
//data access methods...
public Person readPerson(int primaryKey)
{...}
}
Beachten Sie, wie die DataSourceImpl
Instanziierung in einen Konstruktor bewegt wird. Der Konstruktor nimmt vier Parameter, die die vier Werte benötigt durch die DataSourceImpl
sind. Obwohl immer noch die MyDao
Klasse auf diesen vier Werten abhängt, nicht mehr erfüllt diese Abhängigkeiten selbst. Sie werden von was auch immer Klasse eine MyDao
Instanz erstellen.
Die beliebten Antworten sind wenig hilfreich, weil sie Dependency Injection in eine Art und Weise definieren, die nicht nützlich ist. Lassen Sie uns darüber einig, dass durch „Abhängigkeit“ wir einige bereits bestehende andere Objekt, das unser Objekt X Bedürfnisse bedeuten. Aber wir sagen nicht wir tun „Abhängigkeit Injection“, wenn wir sagen,
$foo = Foo->new($bar);
Wir nennen nur, dass Übergabe von Parametern an den Konstruktor. Wir haben seit dem tun, dass regelmäßig jemals Konstrukteurs erfunden wurden.
„Dependency Injection“ ist eine Art von „Inversion of Control“ betrachtet, was bedeutet, dass eine gewisse Logik aus dem Anrufer genommen wird. Das ist nicht der Fall, wenn der Anrufer in Parametern übergibt, so dass, wenn DI sind, DI würde nicht Umkehrung der Kontrolle bedeuten.
DI bedeutet, dass es eine Zwischenstufe zwischen dem Anrufer und dem Konstruktor der Abhängigkeiten schafft. Ein Makefile ist ein einfaches Beispiel für Dependency Injection. Die „Anrufer“ ist die Person, „make Bar“ auf der Kommandozeile, und der „Konstruktor“ ist der Compiler eingeben. Das Makefile gibt an, dass bar auf foo abhängt, und es tut ein
gcc -c foo.cpp; gcc -c bar.cpp
, bevor Sie ein
gcc foo.o bar.o -o bar
Die Person, die Eingabe eines „make bar“ braucht nicht diese Bar zu wissen, hängt von foo. Die Abhängigkeit zwischen "Make bar" injiziert und gcc.
Der Hauptzweck der Zwischenebene ist einfach nicht an den Konstruktor in den Abhängigkeiten passieren, aber all Abhängigkeiten zur Liste in nur an einer Stelle , und sie von dem Codierer zu verstecken (nicht zu macht die Codierer liefern sie).
Normalerweise sind die Zwischenebene bietet Fabriken für die konstruierten Objekte, die eine Rolle zur Verfügung stellen müssen, die jeweils angeforderten Objekttyp erfüllen muss. Das liegt daran, durch einen Zwischenpegel aufweist, der die Details der Konstruktion versteckt, haben Sie bereits die Abstraktion Strafe von Fabriken verhängt entstanden, so dass Sie könnte genauso gut Fabriken verwenden.
Dependency Injection ist eine mögliche Lösung zu dem, was im Allgemeinen der „Abhängigkeit Obfuscation“ Anforderung bezeichnet werden könnte. Dependency Verschleierung ist eine Methode der Einnahme der ‚offensichtlichen‘ Natur aus dem Prozess eine Abhängigkeit zu einer Klasse bereitzustellen, die es erfordert, und deshalb Verschleiern, in irgendeiner Weise die Bereitstellung der Abhängigkeitsklasse gesagt. Dies ist nicht unbedingt eine schlechte Sache. In der Tat, durch die Art und Weise Verschleiern von denen eine Abhängigkeit zu einer Klasse bereitgestellt dann etwas außerhalb der Klasse ist für die Abhängigkeit schaffen, das bedeutet, in verschiedenen Szenarien, eine andere Implementierung der Abhängigkeit kann, ohne dass Änderungen an die Klasse zugeführt werden, zur Klasse. Dies ist ideal für das Umschalten zwischen Produktions- und Testarten (z. B. ein ‚mock‘ Dienstabhängigkeit verwendet wird).
Leider ist das Schlimme, dass einige Menschen, die Sie eine spezielle Rahmen Abhängigkeit Verschleierungs tun müssen, angenommen haben und dass Sie irgendwie ein ‚kleinere‘ Programmierer sind, wenn Sie einen bestimmten Rahmen, es zu tun wählen, zu verwenden. Ein weiterer, äußerst störend Mythos, von vielen geglaubt, dass Dependency Injection ist die einzige Möglichkeit, die Abhängigkeit Verschleierung zu erreichen. Dies ist nachweislich und historisch und natürlich 100% falsch, aber Sie werden Schwierigkeiten haben einige Leute davon zu überzeugen, dass es Alternative Injektion für Ihre Abhängigkeit Verschleierungs Anforderungen Abhängigkeit.
Programmierer die Abhängigkeit Verschleierungspflicht seit Jahren verstanden haben und viele alternative Lösungen entwickelt haben, sowohl vor als auch nach dem Dependency Injection konzipiert wurde. Es gibt Fabrik-Muster, aber es gibt auch viele Optionen Thread mit denen keine Einspritzung zu einer bestimmten Instanz benötigt wird - die Abhängigkeit effektiv in das Gewinde eingespritzt wird, die den Vorteil, dass das Objekt zur Verfügung hat (über Bequemlichkeit statische Getter-Methoden) zu jede Klasse, die es ohne erfordert Anmerkungen zu den Klassen hinzuzufügen, die sie benötigen und komplizierte XML ‚Leim‘ einzurichten, um sie geschehen. Wenn Ihre Abhängigkeiten für die Persistenz erforderlich sind (JPA / JDO oder was auch immer) ermöglicht es Ihnen, ‚tranaparent Beharrlichkeit‘ viel einfacher und mit Domänenmodell und Geschäftsmodellklassen aus rein von POJOs (in Anmerkungen dh keinen Rahmen für spezifischen / gesperrt) zu erreichen.
Aus dem Buch ‚ Fundierte Java Entwickler: Vital Techniken von Java 7 und polyglott Programmierung
DI ist eine besondere Form von IoC, wobei der Prozess Ihre Abhängigkeiten zu finden ist außerhalb der direkten Kontrolle des aktuell ausgeführten Code.
von Book Apress.Spring.Persistence.with.Hibernate.Oct.2010
Der Zweck der Dependency Injection ist die Arbeit von entkoppeln Auflösen externe Software-Komponenten aus Ihrer Anwendung Geschäft logic.Without Dependency Injection, die Details, wie eine Komponente Zugriffe erforderlichen Dienste können mit der Komponente erhalten verworren in Code. Dies erhöht nicht nur das Potenzial für Fehler, fügt Code aufblasen, und vergrößert Wartung Komplexitäten; es koppelt Komponenten mehr eng zusammen, was es schwierig macht Abhängigkeiten zu ändern, wenn Refactoring oder Tests.
Dependency Injection (DI) ist ein von Design Patterns, die den Grundzug des OOP verwendet - die Beziehung in einem Objekt mit einem anderen Objekt. Während Vererbung ein Objekt erbt komplexe und spezifischer auf eine anderes Objekt, Beziehung oder Vereinigung erzeugt einfach einen Zeiger auf ein anderes Objekt von einem Objekt zu tun Attribut. Die Macht der DI ist in Kombination mit anderen Merkmalen der OOP wie sind Schnittstellen und Versteck-Code. Nehmen wir an, wir haben einen Kunden (Teilnehmer) in der Bibliothek, die nur ein Buch der Einfachheit halber ausleihen kann.
Schnittstelle des Buches:
package com.deepam.hidden;
public interface BookInterface {
public BookInterface setHeight(int height);
public BookInterface setPages(int pages);
public int getHeight();
public int getPages();
public String toString();
}
Als nächstes können wir viele Arten von Büchern haben; ein Typ ist Fiktion:
package com.deepam.hidden;
public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages
/** constructor */
public FictionBook() {
// TODO Auto-generated constructor stub
}
@Override
public FictionBook setHeight(int height) {
this.height = height;
return this;
}
@Override
public FictionBook setPages(int pages) {
this.pages = pages;
return this;
}
@Override
public int getHeight() {
// TODO Auto-generated method stub
return height;
}
@Override
public int getPages() {
// TODO Auto-generated method stub
return pages;
}
@Override
public String toString(){
return ("height: " + height + ", " + "pages: " + pages);
}
}
Jetzt können Teilnehmer haben Assoziation zu dem Buch:
package com.deepam.hidden;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Subscriber {
BookInterface book;
/** constructor*/
public Subscriber() {
// TODO Auto-generated constructor stub
}
// injection I
public void setBook(BookInterface book) {
this.book = book;
}
// injection II
public BookInterface setBook(String bookName) {
try {
Class<?> cl = Class.forName(bookName);
Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
BookInterface book = (BookInterface) constructor.newInstance();
//book = (BookInterface) Class.forName(bookName).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return book;
}
public BookInterface getBook() {
return book;
}
public static void main(String[] args) {
}
}
Alle drei Klassen können für seine eigene Implementierung versteckt werden. Jetzt können wir diesen Code für DI verwenden:
package com.deepam.implement;
import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;
public class CallHiddenImplBook {
public CallHiddenImplBook() {
// TODO Auto-generated constructor stub
}
public void doIt() {
Subscriber ab = new Subscriber();
// injection I
FictionBook bookI = new FictionBook();
bookI.setHeight(30); // cm
bookI.setPages(250);
ab.setBook(bookI); // inject
System.out.println("injection I " + ab.getBook().toString());
// injection II
FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
System.out.println("injection II " + ab.getBook().toString());
}
public static void main(String[] args) {
CallHiddenImplBook kh = new CallHiddenImplBook();
kh.doIt();
}
}
Es gibt viele verschiedene Möglichkeiten, wie Dependency Injection zu verwenden. Es ist möglich, es mit Singleton zu kombinieren, etc., aber immer noch in dem Grunde ist es nur Verband realisiert, indem Sie in einem anderen Objekt Attribut des Objekttypen zu schaffen. Der Nutzen ist nur und nur in Funktion, dass Code, die wir wieder schreiben sollen und wieder ist immer vorbereitet und für uns nach vorne getan. Aus diesem Grund DI so eng binded mit Inversion of Control (IoC), was bedeutet, dass unser Programm geht einen anderen Laufmodul steuern, die Injektionen von Bohnen in unseren Code tut. (Jedes Objekt, das unterzeichnet oder als Bean angesehen werden kann injiziert werden kann.) Zum Beispiel im Frühjahr wird es durch die Erstellung und Initialisierung getan Application Behälter, der diese Arbeit für uns. Wir haben einfach in unserem Code, um den Kontext zu erstellen und rufen Sie die Initialisierung der Bohnen. In diesem Moment Injektion wurde automatisch.
In einfachen Worten Abhängigkeitsinjektion (DI) ist die Art und Weise Abhängigkeiten oder enge Kopplung zwischen verschiedenem Objekt zu entfernen. Dependency Injection gibt ein zusammenhängendes Verhalten zu jedem Objekt.
DI ist die Umsetzung der IOC Haupt des Frühlings, die sagt, dass „Sie uns nicht nennen wir rufen“. Dependency Injection Programmiergerät muss nicht Objekt mit dem neuen Schlüsselwort erstellen.
Die Objekte werden im Frühjahr Behälter einmal geladen und dann wir wieder verwenden, wenn wir sie brauchen um diese Objekte aus Federbehälter mit getBean (String BeanName) -Methode abgerufen werden.
Dependency Injection ist das Herz des Konzepts im Zusammenhang mit Feder Framework.While den Rahmen eines Projekt Feder ergeben kann eine wichtige Rolle ausführen, und hier Dependency Injection kam im Krug.
Eigentlich Angenommen in Java erstellt man zwei verschiedene Klassen als Klasse A und Klasse B, und unabhängig von der Funktion in der Klasse B zur Verfügung stehen Sie in der Klasse A verwenden mögen, also zu dieser Zeit Dependency Injection verwendet werden. wo Sie Kiste Objekt einer Klasse in anderen kann auf die gleiche Art und Weise Sie eine ganze Klasse in eine andere Klasse injizieren, um es zugänglich zu machen. auf diese Weise kann die Abhängigkeit überwunden werden.
Dependency Injection ist einfach BELEIMEN ZWEI KLASSEN UND ZUGLEICH sie getrennt zu halten.
Dependency Injection (DI) ist ein Teil der Dependency Inversion Principle (DIP) Praxis, die auch Inversion of Control (IoC) aufgerufen wird. Grundsätzlich müssen Sie DIP tun, weil Sie Ihren Code modularer und Einheit prüfbar, statt nur ein monolithisches System zu machen. So starten Sie Teile des Codes zu identifizieren, die von der Klasse und wegabstrahiert getrennt werden können. Nun ist die Umsetzung der Abstraktion müssen von außerhalb der Klasse injiziert werden. Normalerweise kann dies über Konstruktor erfolgen. So erstellen Sie einen Konstruktor, der die Abstraktion als Parameter akzeptiert, und dies wird als Dependency Injection (via Konstruktor). Weitere Erklärung über DIP, DI und IoC-Container können Sie eine href lesen <= "http://kusnaditjung.blogspot.co.uk/2016/05/dependency-inversion-principle-dip.html" rel = "nofollow" > Hier
Ich würde eine etwas andere, kurz und präzise Definition des Begriffs vorschlagen, was Dependency Injection ist, auf dem primären Ziel konzentrieren, nicht auf die technischen Mittel (in Anlehnung an von hier ):
Dependency Injection ist der Prozess, um die statischen schaffen, stateless Graph von Dienstobjekten, wobei jeder Dienst durch seine parametrisiert wird Abhängigkeiten.
Die Objekte, die wir in unseren Anwendungen erstellen (unabhängig davon, ob wir verwenden Java, C # oder eine andere objektorientierte Sprache) fällt in der Regel in einem von zwei Kategorien: staatenlos, statischer und global „Dienstobjekte“ (Module) und eine Stateful, dynamische und lokale „Datenobjekte“.
Das Modul Graph - die Graph von Dienstobjekten - wird in der Regel auf Start der Anwendung erstellt. Dies kann mit einem Behälter, wie Spring getan wird, kann aber auch manuell durchgeführt werden, durch Übergabe von Parametern Konstrukteuren zu widersprechen. Beide Wege haben ihre Vor- und Nachteile, aber ein Rahmen ist definitiv nicht notwendig DI in Ihrer Anwendung zu verwenden.
Eine Voraussetzung ist, dass die Dienste müssen von ihren Abhängigkeiten parametrisiert werden. Was dies bedeutet, hängt genau auf die Sprache und den Ansatz in einem gegebenen System genommen. Normalerweise dauert dies in Form von Konstruktorparameter, aber Setter verwendet, ist auch eine Option. Dies bedeutet auch, dass die Abhängigkeiten eines Dienstes sind versteckt von den Nutzern des Dienstes (wenn eine Service-Methode aufgerufen wird).
Wenn zu benutzen? Ich würde sagen, wenn die Anwendung groß genug ist, dass die Logik in separate Module Einkapseln mit einem Abhängigkeitsgraphen zwischen den Modulen einem Gewinn an Lesbarkeit und Explorierbarkeit des Codes gibt.
Dependency Injection ist eine Art der Umsetzung der " Inversion of Control " Prinzip, auf dem Frameworks Gebäude basiert.
Frameworks , wie in „Design Pattern“ von GoF sind Klassen angegeben, die die Hauptsteuerablauflogik Erhöhung der Entwickler implementieren, das zu tun, auf diese Weise Frameworks die Umkehrung des Steuerprinzips verwirklichen.
Eine Art und Weise als eine Technik zu implementieren, und nicht als Klassenhierarchie, das IoC Prinzip ist es nur Dependency Injection.
DI besteht hauptsächlich in Delegaten die Zuordnung von Klassen-Instanzen und Typreferenz auf die Instanzen, auf eine externe „Entität“: ein Objekt, statische Klasse, Komponente, Rahmen, etc ...
Klassen-Instanzen sind die " Abhängigkeiten ", die externe Bindung der anrufenden Komponente mit der Klasseninstanz durch die Referenz wird die „ Injektion “.
Natürlich kann man diese Technik in vielen Art und Weise implementieren, wie Sie von OOP Sicht wollen, zum Beispiel finden Sie unter Konstruktor Injektion Setter Injektion -Schnittstelle Injektion .
einen Dritten delegiert die Aufgabe zu erfüllen, ein ref es zu einem Objekt passen ist sehr nützlich, wenn Sie eine Komponente vollständig zu trennen, das einige Dienste von der gleichen Diensten Umsetzung muss.
Auf diese Weise, wenn die Komponenten entwerfen, können Sie sich ausschließlich auf ihrer Architektur und ihre spezifischen Logik konzentrieren, auf Schnittstellen zu vertrauen, um mit anderen Objekten ohne Sorge über jede Art von Implementierungsänderungen von Objekten / Dienstleistungen zusammen verwendet werden, auch wenn das gleiche Objekt Sie verwenden völlig ersetzt werden (natürlich die Schnittstelle zu respektieren).