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?

War es hilfreich?

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,

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,

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 ein ConcreteBar 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 der Disposing 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 newing 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

  1. können wir die Spule im Inneren der Maschine platzieren
  2. 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:

  1. Constructor Injection
  2. 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:

  1. Constructor Injektion
  2. 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:

  1. Unterstützung Dependency Injection, ohne den Konstruktor einer Legacy-Klasse ändern zu müssen.
  2. teure Ressourcen oder Dienste erlaubt so spät wie möglich geschaffen werden, und nur bei Bedarf.
Hier

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 erstellen Service 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 Konstruktor Client betrachten, werden Sie, wie viele Abhängigkeit von Client-Klasse

Nachteile

  • Wenn Sie Constructor Injection verwenden, das Service Objekt erstellt wird, wenn Client erstellt, einmal verwenden wir die Funktion in Client Klasse ohne Verwendung Service so erstellt Service 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 ..

  1. 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?
  2. 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.
  3. 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?
  4. Wenn Aproperty von AClass nicht eingespritzt wird, ist es schwieriger, es zu verspotten?
  5. 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).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top