it-swarm.com.de

Was ist Abhängigkeitsinjektion?

Es wurden bereits einige Fragen mit spezifischen Fragen zur Abhängigkeitsinjektion gepostet, z. B. wann sie verwendet werden sollen und welche Rahmenbedingungen dafür zur Verfügung stehen. Jedoch,

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

2811
AR.

Anstatt dass Ihre Objekte eine Abhängigkeit erzeugen oder ein Factory-Objekt dazu auffordert, eine für sie zu erstellen, übergeben Sie die erforderlichen Abhängigkeiten extern an das Objekt und machen es zu einem Problem eines anderen. Dieser "Jemand" ist entweder ein Objekt weiter oben im Abhängigkeitsgraphen oder ein Abhängigkeitsinjektor (Framework), der den Abhängigkeitsgraphen aufbaut. Eine Abhängigkeit, wie ich sie hier verwende, ist jedes andere Objekt, auf das das aktuelle Objekt einen Verweis halten muss.

Einer der Hauptvorteile der Abhängigkeitseinspritzung besteht darin, dass sie das Testen viel einfacher machen kann. Angenommen, Sie haben ein Objekt, das in seinem Konstruktor Folgendes ausführt:

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

Dies kann mühsam sein, wenn Sie lediglich einige Komponententests mit SomeClass ausführen möchten, insbesondere wenn myObject für komplexe Festplatten oder Netzwerkzugriffe zuständig ist. Sie sehen also jetzt nur myObject, aber auch irgendwie den Werksruf abfangen. Schwer. Übergeben Sie das Objekt stattdessen als Argument an den Konstruktor. Jetzt haben Sie das Problem an einen anderen Ort verschoben, aber das Testen kann viel einfacher werden. Mach einfach ein Dummy myObject und gib das weiter. Der Konstruktor würde jetzt ein bisschen wie folgt aussehen:

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

Dies ist eine Art der Abhängigkeitseingabe - über den Konstruktor. Es sind mehrere Mechanismen möglich. 

  • Wie in den Kommentaren erwähnt, besteht eine häufige Alternative darin, einen Do-Nothing-Konstruktor zu definieren und die Abhängigkeiten über Eigenschaftssetzer (h/t @MikeVella) einzufügen. 
  • Martin Fowler dokumentiert eine dritte Alternative (h/t @MarcDix), bei der Klassen explizit ein Interface für die Abhängigkeiten implementieren, die sie einfügen möchten.

Wenn Sie keine Abhängigkeitseinspritzung verwenden (wie z. B. in Klassen, die in ihren Konstruktoren zu viel Arbeit leisten usw.), wird es oft schwieriger, Komponenten beim Komponententest zu isolieren. 

Als ich 2013 diese Antwort schrieb, war dies ein Hauptthema im Google Testing Blog . Dies ist für mich nach wie vor der größte Vorteil, da Sie möglicherweise nicht immer die zusätzliche Flexibilität in Ihrem Laufzeitdesign benötigen (z. B. für Service Locator oder ähnliche Muster), aber Sie müssen Ihre Klassen häufig während des Testens isolieren können.

1764
wds

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

"Abhängigkeitsinjektion" ist ein 25-Dollar-Betrag Laufzeit für ein 5-Cent-Konzept. [...] Abhängigkeitsinjektion bedeutet ein Objekt seine Instanzvariablen. [...].

Es gibt einen Artikel von Martin Fowler , der sich auch als nützlich erweisen kann.

Bei der Abhängigkeitsinjektion werden im Wesentlichen die Objekte bereitgestellt, die ein Objekt benötigt (seine Abhängigkeiten), anstatt sie selbst erstellen zu lassen. Dies ist eine sehr nützliche Testmethode, da Abhängigkeiten überspottet oder ausgeblendet werden können.

Abhängigkeiten können auf viele Arten in Objekte eingefügt werden (z. B. Konstruktorinjektion oder Setterinjektion). Man kann sogar spezialisierte Abhängigkeitsinjektions-Frameworks (z. B. Spring) verwenden, aber dies ist sicherlich nicht erforderlich. Sie benötigen diese Frameworks nicht, um Abhängigkeiten zu erhalten. Das explizite Instantiieren und Übergeben von Objekten (Abhängigkeiten) ist eine ebenso gute Injektion wie eine Injektion durch das Framework.

2167
Thiago Arrais

Ich fand dieses lustige Beispiel in Bezug auf lose Kopplung :

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

Betrachten Sie beispielsweise ein Car-Objekt.

Ein Car hängt von den Rädern, dem Motor, dem Kraftstoff, der Batterie usw. ab. Traditionell definieren wir die Marke solcher abhängiger Objekte zusammen mit der Definition des Car-Objekts.

Ohne Abhängigkeitseinspritzung (DI):

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

  //The rest
}

Hier ist das Car-Objekt für das Erstellen der abhängigen Objekte verantwortlich.

Was ist, wenn wir den Typ des abhängigen Objekts ändern möchten - sagen Sie Wheel - nach den anfänglichen NepaliRubberWheel()-Punktierungen? Wir müssen das Car-Objekt mit seiner neuen Abhängigkeit, sagen wir ChineseRubberWheel(), neu erstellen. Dies kann jedoch nur der Hersteller Car tun.

Was macht der Dependency Injection dann für ...?

Bei der Verwendung der Abhängigkeitseinspritzung erhalten Objekte ihre Abhängigkeiten zur Laufzeit und nicht zur Kompilierzeit (Fahrzeugherstellungszeit) . Damit wir die Wheel-Datei jetzt jederzeit ändern können. Hier kann dependency (wheel) zur Laufzeit in Car injiziert werden.

Nach der Abhängigkeitsinjektion:

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

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: Abhängigkeitsinjektion verstehen

554
gtiwari333

Abhängigkeitsinjektion ist eine Praxis, bei der Objekte so entworfen werden, dass sie Instanzen der Objekte von anderen Codeteilen erhalten, anstatt sie intern zu erstellen. Dies bedeutet, dass jedes Objekt, das die Schnittstelle implementiert, das von dem Objekt benötigt wird, ohne Änderung des Codes ersetzt werden kann, was das Testen vereinfacht und die Entkopplung verbessert.

Betrachten Sie zum Beispiel diese Klassen:

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

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

In diesem Beispiel würde die Implementierung von PersonService::addManager und PersonService::removeManager eine Instanz der GroupMembershipService benötigen, um ihre Arbeit zu erledigen. Ohne Abhängigkeitsinjektion würde dies herkömmlicherweise die Instanz eines neuen GroupMembershipService im Konstruktor von PersonService sein und dieses Instanzattribut in beiden Funktionen verwenden. Wenn der Konstruktor von GroupMembershipService jedoch mehrere Dinge benötigt oder, was noch schlimmer ist, gibt es einige Initialisierungs-Setter, die für die GroupMembershipService aufgerufen werden müssen, der Code wächst ziemlich schnell und die PersonService hängt jetzt nicht nur von der GroupMembershipService ab, sondern auch alles andere, von dem GroupMembershipService abhängt. Darüber hinaus ist die Verknüpfung zu GroupMembershipService in PersonService hartcodiert. Dies bedeutet, dass Sie eine GroupMembershipService nicht zu Testzwecken "dummy-up" machen oder ein Strategiemuster in verschiedenen Teilen Ihrer Anwendung verwenden können. 

Mit Dependency Injection können Sie die GroupMembershipService in Ihrer PersonService nicht instanziieren, sondern entweder an den PersonService-Konstruktor übergeben oder eine Property (Getter und Setter) hinzufügen, um eine lokale Instanz davon festzulegen. Dies bedeutet, dass sich Ihre PersonService nicht länger um die Erstellung einer GroupMembershipService kümmern muss, sie akzeptiert nur die angegebenen Variablen und arbeitet mit ihnen. Dies bedeutet auch, dass alles, was eine Unterklasse von GroupMembershipService ist oder die GroupMembershipService-Schnittstelle implementiert, in die PersonService "injiziert" werden kann und die PersonService keine Kenntnis von der Änderung haben muss.

241
Adam Ness

Die akzeptierte Antwort ist gut - aber ich möchte hinzufügen, dass DI dem klassischen Vermeiden von fest codierten Konstanten im Code sehr ähnlich ist. 

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

DI ist in der Welt der objektorientierten Programmierung analog. Die Werte anstelle von konstanten Literalen sind ganze Objekte. Der Grund für das Verschieben des Codes aus dem Klassencode ist jedoch ähnlich - die Objekte ändern sich häufiger als der Code, der sie verwendet. Ein wichtiger Fall, in dem eine solche Änderung erforderlich ist, sind Tests.

155
zby

Versuchen wir es mit einem einfachen Beispiel mit den Klassen Car und Engine. Jedes Auto benötigt einen Motor, um zumindest irgendwohin zu gehen. Im Folgenden wird beschrieben, wie der Code ohne Abhängigkeitseingabe 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!");
    }
}

Um die Autoklasse zu instanziieren, verwenden wir den nächsten Code:

Car car = new Car();

Das Problem mit diesem Code, dass wir eng mit GasEngine gekoppelt sind, und wenn wir uns entscheiden, es in ElectricityEngine zu ändern, müssen wir die Car-Klasse neu schreiben. Und je größer die Anwendung, desto mehr Probleme und Kopfschmerzen müssen wir hinzufügen und verwenden, um einen neuen Motortyp zu verwenden. 

Mit anderen Worten, bei diesem Ansatz ist unsere High-Level-Klasse Car von der Klasse GasEngine der unteren Ebene abhängig, die gegen das Abhängigkeitsinversionsprinzip (DIP) von SOLID verstößt. DIP legt nahe, dass wir uns auf Abstraktionen verlassen sollten, nicht auf konkrete Klassen. Um dies zu befriedigen, führen wir die IEngine-Schnittstelle ein und schreiben den Code wie folgt um:

    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 Klasse Car nur von der IEngine-Schnittstelle abhängig, nicht von einer bestimmten Implementierung der Engine. Der einzige Trick ist nun, wie wir eine Instanz des Autos erstellen und ihm eine konkrete konkrete Motorklasse wie GasEngine oder ElectricityEngine zuweisen. Hier kommt Abhängigkeitsinjektion ins Spiel. 

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Hier geben wir unsere Abhängigkeit (Engine-Instanz) grundsätzlich an den Car-Konstruktor weiter. Nun haben unsere Klassen eine lose Kopplung zwischen Objekten und deren Abhängigkeiten, und wir können problemlos neue Motortypen hinzufügen, ohne die Klasse Car zu ändern.

Der Hauptvorteil von Dependency Injection besteht darin, dass Klassen lose gekoppelt sind, da sie keine fest codierten Abhängigkeiten haben. Dies folgt dem Prinzip der Inversion der Abhängigkeit, das oben erwähnt wurde. Anstatt auf bestimmte Implementierungen zu verweisen, fordern Klassen Abstraktionen an (normalerweise Interface), die ihnen bei der Erstellung der Klasse zur Verfügung gestellt werden.

Am Ende ist Dependency Injection nur eine Technik für lockere Kopplung zwischen Objekten und ihren Abhängigkeiten . Anstatt die Abhängigkeiten, die die Klasse in .__ benötigt, nicht direkt zu instanziieren. Um seine Aktionen auszuführen, werden der Klasse Abhängigkeiten zur Verfügung gestellt (am häufigsten) über Konstruktorinjektion.

Wenn wir viele Abhängigkeiten haben, ist es sehr empfehlenswert, Inversion of Control (IoC) -Container zu verwenden, um festzustellen, welche Schnittstellen für alle unsere Abhängigkeiten bestimmten Implementierungen zugeordnet werden sollten unser Objekt Zum Beispiel könnten wir im Mapping für den IoC-Container angeben, dass die Abhängigkeit von IEngine der Klasse GasEngine zugeordnet werden soll, und wenn wir den IoC-Container nach einer Instanz unserer Klasse Car fragen erstellt automatisch unsere Car - Klasse mit einer übergebenen GasEngine - Abhängigkeit. 

UPDATE: Vor kurzem beobachtete ich den Kurs über EF Core von Julie Lerman und mochte auch ihre kurze Definition über DI.

Abhängigkeitsinjektion ist ein Muster, mit dem Ihre Anwendung Injizieren kann. fliegende Objekte für Klassen, die sie benötigen, ohne diese .__ zu erzwingen. Klassen, die für diese Objekte verantwortlich sind. Damit kann Ihr Code .__ sein. locker gekoppelt, und Entity Framework Core wird in dieselbe System von Dienstleistungen.

103
user2771704

Stellen wir uns vor, Sie wollen angeln gehen:

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

  • Mit der Abhängigkeitseinspritzung kümmert sich ein anderer um die Vorbereitung und stellt Ihnen die erforderliche Ausrüstung zur Verfügung. Sie werden das Boot, die Angelrute und den Köder erhalten ("injiziert") - alles einsatzbereit.

102
Olivier Liechti

Dies ist die einfachste Erklärung für Dependency Injection und Dependency Injection Container, die ich je gesehen habe:

Ohne Abhängigkeitsinjektion

  • Die Anwendung benötigt Foo (z. B. einen Controller).
  • Anwendung erstellt Foo
  • Anwendung ruft Foo .__ auf.
    • Foo braucht eine Bar (z. B. einen Dienst), also:
    • Foo schafft Bar
    • Foo ruft Bar an
      • Bar braucht Bim (einen Dienst, ein Repository, …), Also:
      • Bar erstellt Bim
      • Bar macht etwas

Mit Abhängigkeitsinjektion

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

Verwenden eines Abhängigkeitsinjektionscontainers

  • Bewerbungsbedarf Foo so:
  • Anwendung erhält Foo aus dem Container, also:
    • Container erstellt Bim
    • Container erstellt Bar und gibt es Bim
    • Container erstellt Foo und gibt ihm Bar
  • Anwendung ruft Foo .__ auf.
    • Foo ruft Bar an
      • Bar macht etwas

Dependency Injection und Dependency Injection Containers sind verschiedene Dinge:

  • Abhängigkeitsinjektion ist eine Methode zum Schreiben von besserem Code
  • ein DI-Container ist ein Werkzeug, mit dessen Hilfe Abhängigkeiten eingefügt werden können

Sie benötigen keinen Container für die Abhängigkeitsinjektion. Ein Container kann Ihnen jedoch helfen.

86
Trix

Bedeutet "Abhängigkeitsinjektion" nicht nur parametrisierte Konstruktoren und öffentliche Setter?

James Shores Artikel zeigt die folgenden Vergleichsbeispiele .

Konstruktor ohne Abhängigkeitsinjektion:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Konstruktor mit Abhängigkeitsinjektion:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}
49
JaneGoodall

Was ist Abhängigkeitsinjektion (DI)?

Wie bereits erwähnt, beseitigt Dependency Injection (DI) die Verantwortung für die direkte Erstellung und Verwaltung der Lebensdauer anderer Objektinstanzen, auf die sich unsere Interessenklasse (Verbraucherklasse) bezieht abhängig (im ML-Sinne ). Diese Instanzen werden stattdessen an unsere Consumer-Klasse übergeben, in der Regel als Konstruktorparameter oder über Eigenschaftssetter (die Verwaltung der Instanzierung des Abhängigkeitsobjekts und die Übergabe an die Consumer-Klasse erfolgt normalerweise durch eine Inversion of Control (IoC). Container, aber das ist ein anderes Thema).

DI, DIP und SOLID

Insbesondere im Paradigma von Robert C. Martins SOLID-Prinzipien des objektorientierten Designs ist DI eine der möglichen Implementierungen des Dependency Inversion Principle (DIP) . Das DIP ist das D des SOLID-Mantras - Andere DIP-Implementierungen umfassen den Service Locator und Plugin-Muster.

Ziel des DIP ist es, enge, konkrete Abhängigkeiten zwischen Klassen zu entkoppeln und stattdessen die Kopplung durch eine Abstraktion zu lösen, die je nach Sprache und Ansatz über einen interface, abstract class oder pure virtual class erreicht werden kann.

Ohne das DIP ist unser Code (ich habe diese "konsumierende Klasse" genannt) direkt mit einer konkreten Abhängigkeit verbunden und ist oft auch mit der Verantwortung belastet, zu wissen, wie eine Instanz dieser Abhängigkeit abgerufen und verwaltet wird, d. H. Konzeptionell:

"I need to create/use a Foo and invoke method `GetBar()`"

Während nach Anwendung des DIP die Anforderung gelockert wird und die Sorge, die Lebensdauer der Abhängigkeit Foo zu erhalten und zu verwalten, beseitigt wurde:

"I need to invoke something which offers `GetBar()`"

Warum DIP (und DI) verwenden?

Das Entkoppeln von Abhängigkeiten zwischen Klassen auf diese Weise ermöglicht ein einfaches Ersetzen dieser Abhängigkeitsklassen durch andere Implementierungen, die auch die Voraussetzungen der Abstraktion erfüllen (z. B. kann die Abhängigkeit durch eine andere Implementierung der umgeschaltet werden) gleiche Schnittstelle). Darüber hinaus besteht, wie andere bereits erwähnt haben, möglicherweise der häufigste Grund für die Entkopplung von Klassen über das DIP darin, dass eine konsumierende Klasse isoliert getestet werden kann, da dieselben Abhängigkeiten nun gestubbt werden können und/oder verspottet.

Eine Konsequenz von DI ist, dass das Lebensdauermanagement von Abhängigkeitsobjektinstanzen nicht mehr von einer konsumierenden Klasse gesteuert wird, da das Abhängigkeitsobjekt jetzt an die konsumierende Klasse übergeben wird (über Konstruktor- oder Setter-Injection).

Dies kann auf verschiedene Arten angezeigt werden:

  • Wenn die Kontrolle über die Lebensdauer der Abhängigkeiten durch die konsumierende Klasse beibehalten werden muss, kann die Kontrolle wiederhergestellt werden, indem eine (abstrakte) Factory zum Erstellen der Abhängigkeitsklasseninstanzen in die Konsumentenklasse eingefügt wird. Der Verbraucher kann Instanzen nach Bedarf über Create im Werk abrufen und diese Instanzen nach Abschluss entsorgen.
  • Alternativ kann die Lebensdauerkontrolle von Abhängigkeitsinstanzen auf einen IoC-Container übertragen werden (mehr dazu weiter unten).

Wann wird DI verwendet?

  • Wo es wahrscheinlich notwendig sein wird, eine Abhängigkeit durch eine äquivalente Implementierung zu ersetzen,
  • Jederzeit, wenn Sie die Methoden einer Klasse einzeln für ihre Abhängigkeiten testen müssen,
  • Wenn die Ungewissheit über die Lebensdauer einer Abhängigkeit ein Experimentieren rechtfertigt (z. B. ist Hey, MyDepClass threadsicher - was ist, wenn wir es zu einem Singleton machen und allen Konsumenten dieselbe Instanz injizieren?)

Beispiel

Hier ist eine einfache C # -Implementierung. In Anbetracht der folgenden Verbraucherklasse:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Obwohl es scheinbar harmlos ist, gibt es zwei static-Abhängigkeiten von zwei anderen Klassen, System.DateTime und System.Console, die nicht nur die Optionen für die Protokollausgabe einschränken (Protokollierung auf der Konsole ist wertlos, wenn niemand zugreift), sondern es ist noch schlimmer, wenn sie automatisch getestet werden die Abhängigkeit von einer nicht deterministischen Systemuhr.

Wir können jedoch DIP auf diese Klasse anwenden, indem wir das Problem der Zeitstempelung als Abhängigkeit abstrahieren und MyLogger nur auf eine einfache Schnittstelle koppeln:

public interface IClock
{
    DateTime Now { get; }
}

Wir können auch die Abhängigkeit von Console von einer Abstraktion wie TextWriter lösen. Die Abhängigkeitsinjektion wird in der Regel als constructor -Injektion (Übergabe einer Abstraktion an eine Abhängigkeit als Parameter an den Konstruktor einer konsumierenden Klasse) oder Setter Injection (Übergabe der Abhängigkeit über einen setXyz() -Setter oder eine .Net-Eigenschaft mit {set;} definiert). Konstruktorinjektion wird bevorzugt, da dies garantiert, dass die Klasse nach der Erstellung einen korrekten Status aufweist und die internen Abhängigkeitsfelder als readonly (C #) oder final (Java) gekennzeichnet werden können. Wenn Sie also die Konstruktorinjektion im obigen Beispiel verwenden, erhalten Sie:

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

(Es muss ein konkretes Clock bereitgestellt werden, das natürlich auf DateTime.Now zurückgesetzt werden kann, und die beiden Abhängigkeiten müssen von einem IoC-Container per Konstruktorinjektion bereitgestellt werden.)

Es kann ein automatisierter Unit Test erstellt werden, der definitiv beweist, dass unser Logger korrekt funktioniert, da wir nun die Kontrolle über die Abhängigkeiten haben - die Zeit - und wir können die geschriebene Ausgabe ausspionieren:

[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());
}

Nächste Schritte

Die Abhängigkeitsinjektion ist immer mit einem Inversion of Control-Container (IoC) verknüpft, um die konkreten Abhängigkeitsinstanzen zu injizieren (bereitzustellen) und die Lebensdauerinstanzen zu verwalten. Während des Konfigurations-/Bootstrapping-Vorgangs können in IoC-Containern folgende Elemente definiert werden:

  • zuordnung zwischen jeder Abstraktion und der konfigurierten konkreten Implementierung (z. B. "Immer wenn ein Verbraucher eine IBar-Instanz anfordert, wird eine ConcreteBar-Instanz zurückgegeben" )
  • richtlinien können für das Lebensdauermanagement jeder Abhängigkeit eingerichtet werden, z. Erstellen eines neuen Objekts für jede Konsumenteninstanz, Freigeben einer Singleton-Abhängigkeitsinstanz für alle Konsumenten, Freigeben derselben Abhängigkeitsinstanz nur für denselben Thread usw.
  • In .Net sind IoC-Container mit Protokollen wie IDisposable vertraut und übernehmen die Verantwortung für Disposing-Abhängigkeiten entsprechend der konfigurierten Lebensdauerverwaltung.

Sobald IoC-Container konfiguriert/gebootet wurden, arbeiten sie in der Regel nahtlos im Hintergrund, sodass sich der Codierer auf den jeweiligen Code konzentrieren kann, ohne sich um Abhängigkeiten kümmern zu müssen.

Der Schlüssel zu DI-freundlichem Code besteht darin, die statische Kopplung von Klassen zu vermeiden und new () nicht zum Erstellen von Abhängigkeiten zu verwenden

Wie im obigen Beispiel erfordert das Entkoppeln von Abhängigkeiten einen gewissen Entwicklungsaufwand, und für den Entwickler ist ein Paradigmenwechsel erforderlich, um die Gewohnheit aufzuheben, Abhängigkeiten new direkt zu behandeln und stattdessen dem Container zu vertrauen, um Abhängigkeiten zu verwalten.

Aber es gibt viele Vorteile, insbesondere in Bezug auf die Möglichkeit, Ihre Interessengruppe gründlich zu testen.

Hinweis : Die Erstellung/Zuordnung/Projektion (über new ..()) von POCO/POJO/Serialization DTOs/Entity Graphs/Anonymous JSON-Projektionen et al. - dh "Nur Daten" -Klassen oder Datensätze -, die von Methoden verwendet oder zurückgegeben werden, werden nicht als Abhängigkeiten (im UML-Sinne) betrachtet und unterliegen nicht DI. Es ist in Ordnung, new zu verwenden, um diese zu projizieren.

36
StuartLC

Konzept der Abhängigkeitsinjektion verständlich machen. Nehmen wir ein Beispiel für den Schalterknopf, um eine Glühlampe ein- oder auszuschalten.

Ohne Abhängigkeitsinjektion

Der Switch muss vorher wissen, an welche Glühlampe ich angeschlossen bin (hartcodierte Abhängigkeit). So,

Schalter -> PermanentBulb / Schalter ist direkt an eine permanente Glühlampe angeschlossen; Testung nicht problemlos möglich

/ - 

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Mit Abhängigkeitsinjektion

Switch weiß nur, dass ich die Bulb, die mir übergeben wird, ein-/ausschalten muss. So,

Switch -> Bulb1 OR Bulb2 OR NightBulb (injizierte Abhängigkeit)

 

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

James Beispiel für Schalter und Glühlampe ändern:

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(); 
    ... 
  } 
}`
33
wakqasahmed

Der Sinn von Dependency Injection (DI) ist es, den Quellcode der Anwendung clean und stabil zu halten :

  • clean des Initialisierungscodes für die Abhängigkeit
  • stable unabhängig von der verwendeten Abhängigkeit

In der Praxis trennt jedes Entwurfsmuster die Bedenken, damit zukünftige Änderungen die Mindestanzahl von Dateien beeinflussen.

Die spezifische Domäne von DI ist die Delegierung der Abhängigkeitskonfiguration und -initialisierung.

Beispiel: DI mit Shell-Skript

Wenn Sie gelegentlich außerhalb von Java arbeiten, denken Sie daran, wie source häufig in vielen Skriptsprachen verwendet wird (Shell, Tcl usw. oder sogar import in Python, die zu diesem Zweck verwendet werden).

Betrachten Sie das einfache dependent.sh-Skript:

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Das Skript ist abhängig: Es wird nicht erfolgreich alleine ausgeführt (archive_files ist nicht definiert).

Sie definieren archive_files im archive_files_Zip.sh-Implementierungsskript (in diesem Fall mit Zip):

#!/bin/sh
# Dependency
function archive_files {
    Zip files.Zip "[email protected]"
}

Anstatt source- Implementierungsskript direkt im abhängigen Skript zu verwenden, verwenden Sie einen injector.sh "Container", der beide "Komponenten" umschließt:

#!/bin/sh 
# Injector
source ./archive_files_Zip.sh
source ./dependent.sh

Der archive_filesAbhängigkeit wurde gerade injiziert in abhängig Skript.

Sie könnten eine Abhängigkeit eingefügt haben, die archive_files mithilfe von tar oder xz implementiert.

Beispiel: Entfernen von DI

Wenn dependent.sh-Skript Abhängigkeiten direkt verwendet, heißt der Ansatz Abhängigkeitsabfrage (was sich entgegengesetzt zu Abhängigkeitseinspritzung handelt:

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_Zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Nun besteht das Problem darin, dass die abhängige "Komponente" die Initialisierung selbst durchführen muss.

Der Quellcode der "Komponente" ist nicht clean noch stable , da für jede Änderung der Initialisierung von Abhängigkeiten ein neues Release für die Quellcodedatei von "Komponenten" erforderlich ist.

Letzte Worte

DI wird nicht so stark betont und popularisiert wie in Java-Frameworks.

Es ist jedoch ein generischer Ansatz, um die Bedenken zu trennen:

  • anwendung Entwicklung ( Single Quellcode-Release-Lebenszyklus)
  • anwendung Bereitstellung ( Multiple Zielumgebungen mit unabhängigen Lebenszyklen)

Die Verwendung der Konfiguration nur mit Abhängigkeitsabfrage hilft nicht, da sich die Anzahl der Konfigurationsparameter je Abhängigkeit (z. B. neuer Authentifizierungstyp) sowie die Anzahl der unterstützten Arten von Abhängigkeiten (z. B. neuer Datenbanktyp) ändern kann.

25
uvsmtid

Alle obigen Antworten sind gut, mein Ziel ist es, das Konzept auf einfache Weise zu erklären, so dass jeder ohne Programmierkenntnisse auch das Konzept verstehen kann

Die Abhängigkeitsinjektion ist eines der Entwurfsmuster, die uns helfen, komplexe Systeme auf einfachere Weise zu erstellen.

Wir können eine Vielzahl von Anwendungen dieses Musters in unserem täglichen Leben beobachten. Einige der Beispiele sind Kassettenrekorder, VCD, CD-Laufwerk usw.

Reel-to-reel portable tape recorder, mid-20th century.

Das obige Bild zeigt ein tragbares Tonbandgerät von Band zu Band, Mitte des 20. Jahrhunderts. Quelle .

Die Hauptabsicht eines Tonbandgeräts besteht darin, Ton aufzunehmen oder wiederzugeben.

Beim Entwerfen eines Systems ist eine Rolle erforderlich, um Ton oder Musik aufzunehmen oder wiederzugeben. Es gibt zwei Möglichkeiten, dieses System zu entwerfen

  1. wir können die Rolle in die Maschine legen
  2. wir können einen Haken für die Rolle bereitstellen, an dem sie platziert werden kann.

Wenn wir die erste verwenden, müssen wir die Maschine öffnen, um die Rolle zu wechseln. Wenn wir uns für die zweite Variante entscheiden, bei der ein Haken für die Rolle platziert wird, erhalten wir einen zusätzlichen Vorteil, wenn wir Musik abspielen, indem wir die Rolle wechseln. und auch die Funktion zu reduzieren, nur um zu spielen, was auch immer in der Rolle ist.

Ebenso wie bei der Abhängigkeitsinjektion werden die Abhängigkeiten ausgelagert, um sich nur auf die spezifische Funktionalität der Komponente zu konzentrieren, sodass unabhängige Komponenten zu einem komplexen System verbunden werden können.

Die Hauptvorteile, die wir mit der Abhängigkeitsinjektion erzielt haben.

  • Hohe Kohäsion und lose Kopplung.
  • Abhängigkeit externalisieren und nur auf Verantwortung schauen.
  • Dinge zu Komponenten machen und zu einem großen System mit hohen Fähigkeiten zu kombinieren.
  • Es hilft, qualitativ hochwertige Komponenten zu entwickeln, da diese unabhängig voneinander entwickelt und ordnungsgemäß getestet werden.
  • Es ist hilfreich, die Komponente durch eine andere zu ersetzen, wenn eine ausfällt.

Heute bildet dieses Konzept die Grundlage bekannter Frameworks in der Programmierwelt. The Spring Angular etc sind die bekannten Software-Frameworks, die auf diesem Konzept aufbauen

Die Abhängigkeitsinjektion ist ein Muster, das zum Erstellen von Instanzen von Objekten verwendet wird, auf die sich andere Objekte stützen, ohne beim Kompilieren zu wissen, welche Klasse verwendet wird, um diese Funktionalität bereitzustellen, oder einfach, wie Eigenschaften in ein Objekt injiziert werden.

Beispiel für die Abhängigkeitsinjektion

Bisher haben wir Code wie diesen geschrieben

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 der Abhängigkeitsinjektion entfernt der Abhängigkeitsinjektor die Instanziierung für uns

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

nterschied zwischen Inversion der Kontrolle und Abhängigkeitsinjektion

19
Samuel J Mathew

Was ist Abhängigkeitsinjektion?

Dependency Injection (DI) bedeutet, die voneinander abhängigen Objekte zu entkoppeln. Angenommen, Objekt A ist von Objekt B abhängig, so dass die Idee besteht, diese Objekte voneinander zu entkoppeln. Wir müssen das Objekt nicht hart codieren, sondern müssen trotz der Kompilierzeit Abhängigkeiten zu Objekten zur Laufzeit freigeben. Wenn wir darüber sprechen 

So funktioniert Dependency Injection im Frühling:

Wir müssen das Objekt nicht mit einem neuen Schlüsselwort hart codieren, sondern die Bean-Abhängigkeit in der Konfigurationsdatei definieren. Der Federbehälter ist für das Anschließen aller verantwortlich.

Inversion der Kontrolle (IOC)

IOC ist ein allgemeines Konzept und kann auf viele verschiedene Arten ausgedrückt werden. Abhängigkeitseinspritzung ist ein konkretes Beispiel für IOC.

Zwei Arten von Abhängigkeitseinspritzung:

  1. Konstruktorinjektion
  2. Setter-Injektion

1. Konstruktor-basierte Abhängigkeitsinjektion:

Konstruktor-basierte DI wird ausgeführt, wenn der Container einen Klassenkonstruktor mit einer Reihe von Argumenten aufruft, die jeweils eine Abhängigkeit von einer anderen Klasse darstellen.

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 Abhängigkeitsinjektion:

Setter-based DI wird durch den Container erreicht, der Setter-Methoden für Ihre Beans aufruft, nachdem ein Konstruktor ohne Argumente oder eine statische Factory-Methode ohne Argument aufgerufen wurde, um Ihr Bean zu instantiieren.

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 Faustregel, Konstruktorargumente für zwingende Abhängigkeiten und Setter für optionale Abhängigkeiten zu verwenden. Beachten Sie, dass die Annotation, die als @Required-Annotation für einen Setter verwendet wird, verwendet werden kann, um Setter als erforderliche Abhängigkeiten zu erstellen.

17
Harleen

Die beste Analogie, die ich mir vorstellen kann, ist der Chirurg und seine Assistenten in einem Operationssaal, in dem der Chirurg die Hauptperson ist, und sein Assistent, der die verschiedenen chirurgischen Komponenten zur Verfügung stellt, wenn er sie benötigt, damit der Chirurg sich auf den einen konzentrieren kann was er am besten kann (Operation). Ohne den Assistenten muss der Chirurg die Komponenten jedes Mal selbst holen, wenn er eines benötigt.

DI, kurz DI, ist eine Technik, um eine gemeinsame zusätzliche Verantwortung (Belastung) für Komponenten zu beseitigen, um die abhängigen Komponenten abzurufen, indem sie ihnen zur Verfügung gestellt werden.

DI bringt Sie dem Single-Responsibility-Prinzip (SR) wie dem surgeon who can concentrate on surgery näher.

Wann sollte DI verwendet werden? Ich würde die Verwendung von DI in fast allen Produktionsprojekten (klein/groß) empfehlen, insbesondere in sich ständig ändernden Geschäftsumgebungen :)

Warum: Weil Sie möchten, dass Ihr Code einfach testbar ist, verspottet usw., damit Sie Ihre Änderungen schnell testen und auf den Markt bringen können. Abgesehen davon, warum sollten Sie es nicht tun, wenn Sie viele tolle kostenlose Tools/Frameworks zur Verfügung stellen, die Sie auf Ihrem Weg zu einer Codebasis unterstützen, in der Sie mehr Kontrolle haben.

15
Anwar Husain

Das bedeutet, dass Objekte nur so viele Abhängigkeiten haben sollten, wie sie für ihre Arbeit benötigen, und dass die Abhängigkeiten gering sein sollten. Des Weiteren sollten die Abhängigkeiten eines Objekts auf Schnittstellen und nicht auf "konkrete" Objekte sein, wenn dies möglich ist. (Ein konkretes Objekt ist ein Objekt, das mit dem Schlüsselwort new erstellt wurde.) Eine lose Kopplung fördert die Wiederverwendbarkeit, die Wartungsfreundlichkeit und die einfache Bereitstellung von „Scheinobjekten“ anstelle von teuren Services.

Die "Dependency Injection" (DI) wird auch als "Inversion of Control" (IoC) bezeichnet und kann als Technik zur Förderung dieser lockeren Kopplung verwendet werden.

Es gibt zwei Hauptansätze zur Implementierung von DI:

  1. Konstruktorinjektion 
  2. Setterinjektion

Konstruktorinjektion

Hierbei handelt es sich um die Technik, Objekte Abhängigkeiten an den Konstruktor zu übergeben.

Beachten Sie, dass der Konstruktor eine Schnittstelle und kein konkretes Objekt akzeptiert. Beachten Sie außerdem, dass eine Ausnahme ausgelöst wird, wenn der Parameter orderDao den Wert null hat. Dies unterstreicht die Wichtigkeit, eine gültige Abhängigkeit zu erhalten. Constructor Injection ist meiner Meinung nach der bevorzugte Mechanismus, um einem Objekt seine Abhängigkeiten zu geben. Dem Entwickler ist beim Aufrufen des Objekts klar, welche Abhängigkeiten dem Objekt "Person" für eine ordnungsgemäße Ausführung zugewiesen werden müssen.

Setter-Injektion

Beachten Sie jedoch folgendes Beispiel: Angenommen, Sie haben eine Klasse mit zehn Methoden, die keine Abhängigkeiten haben, aber Sie fügen eine neue Methode hinzu, die von IDAO abhängig ist. Sie können den Konstruktor so ändern, dass er Konstruktorinjektion verwendet. Dies kann Sie jedoch dazu zwingen, Änderungen an allen Konstruktoraufrufen überall vorzunehmen. Alternativ können Sie einfach einen neuen Konstruktor hinzufügen, der die Abhängigkeit übernimmt, aber dann weiß ein Entwickler leicht, wann er einen Konstruktor über dem anderen verwenden soll. Wenn die Abhängigkeit sehr teuer ist, warum sollte sie erstellt und an den Konstruktor übergeben werden, wenn sie nur selten verwendet wird? "Setter Injection" ist eine weitere DI-Technik, die in solchen Situationen eingesetzt werden kann.

Setter Injection erzwingt keine Weitergabe von Abhängigkeiten an den Konstruktor. Stattdessen werden die Abhängigkeiten auf öffentliche Eigenschaften festgelegt, die von dem betreffenden Objekt verfügbar gemacht werden. Wie zuvor angedeutet, sind die Hauptmotivatoren dafür:

  1. Unterstützung der Abhängigkeitsinjektion, ohne den Konstruktor einer älteren Klasse ändern zu müssen.
  2. So können teure Ressourcen oder Dienste so spät wie möglich und nur bei Bedarf erstellt werden.

Hier ist das Beispiel, 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;
13

Wir haben beispielsweise 2 Klassen Client und Service. Client verwendet Service

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Ohne Abhängigkeitsinjektion

Weg 1) 

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Weg 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Weg 3) 

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) Verwendung von

Client client = new Client();
client.doSomeThingInService();

Vorteile

  • Einfach

Nachteile

  • Hart für den Test Client Klasse
  • Wenn wir den Service Konstruktor ändern, müssen wir den Code an allen Stellen des Service Objektes ändern

Verwenden Sie Abhängigkeitsinjektion

Möglichkeit 1) Konstruktorinjektion

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

Verwenden 

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Weg 2) Setterinjektion

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Verwenden 

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Weg 3) Schnittstelleninjektion

Überprüfen Sie https://en.wikipedia.org/wiki/Dependency_injection

=== 

Nun folgt dieser Code Dependency Injection und ist einfacher für die test Client Klasse.
Allerdings verwenden wir new Service() immer noch oft und es ist nicht gut, wenn Sie den Service Konstruktor ändern. Um dies zu verhindern, können wir DI-Injektor gerne verwenden
1) Einfaches Handbuch 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(...));
    }
}

Verwenden von

Service service = Injector.provideService();

2) Verwenden Sie die Bibliothek: Für Android dagger2

Vorteile

  • Machen Sie den Test einfacher
  • Wenn Sie Service ändern, müssen Sie es nur in der Injector-Klasse ändern
  • Wenn Sie Constructor Injection verwenden, wenn Sie den Konstruktor von Client betrachten, sehen Sie, wie viele Abhängigkeiten von der Client Klasse bestehen

Nachteile 

  • Wenn Sie use Constructor Injection verwenden, wird das Service Objekt erstellt, wenn Client erstellt wird. Manchmal werden Funktionen in der Client Klasse verwendet, ohne dass Service so erstellt wird Service

Definition der Abhängigkeitsinjektion

https://en.wikipedia.org/wiki/Dependency_injection

Eine Abhängigkeit ist ein Objekt, das verwendet werden kann (Service)
Eine Injektion ist die Übergabe einer Abhängigkeit (Service) an ein abhängiges Objekt (Client), das sie verwenden würde

12
Linh

Ich denke, da jeder für DI geschrieben hat, lassen Sie mich ein paar Fragen stellen.

  1. Wenn Sie über eine DI-Konfiguration verfügen, bei der alle tatsächlichen Implementierungen (nicht Schnittstellen), die in eine Klasse eingefügt werden sollen (z. B. Dienste für einen Controller), warum handelt es sich dann nicht um eine Art Hardcoding? 
  2. Was ist, wenn ich das Objekt zur Laufzeit ändern möchte? Zum Beispiel sagt meine Konfiguration bereits, wenn ich MyController instanziiere, für FileLogger als ILogger einspritze. Aber ich möchte DatabaseLogger injizieren. 
  3. Jedes Mal, wenn ich ändern möchte, welche Objekte meine AClass benötigt, muss ich jetzt an zwei Stellen nachsehen - in die Klasse selbst und in die Konfigurationsdatei. Wie macht das das Leben leichter?
  4. Wenn Aproperty of AClass nicht eingespritzt wird, ist es schwieriger, es zu verspotten? 
  5. Zurück zur ersten Frage. Wenn die Verwendung des neuen Objekts () schlecht ist, wie werden dann die Implementierung und nicht die Schnittstelle eingefügt? Ich denke, viele von Ihnen sagen, dass wir die Schnittstelle tatsächlich einschleusen, aber durch die Konfiguration müssen Sie die Implementierung dieser Schnittstelle angeben ... nicht zur Laufzeit. Sie wird während der Kompilierungszeit fest codiert.

Dies basiert auf der Antwort @Adam N gepostet.

Warum muss sich PersonService nicht mehr um GroupMembershipService kümmern? Sie haben gerade erwähnt, dass GroupMembership mehrere Dinge (Objekte/Eigenschaften) hat, von denen es abhängt. Wenn GMService in PService erforderlich ist, haben Sie es als Eigenschaft. Sie können das ausspielen, unabhängig davon, ob Sie es injiziert haben oder nicht. Ich möchte nur, dass es injiziert wird, wenn GMService spezifischere untergeordnete Klassen hätte, die Sie bis zur Laufzeit nicht kennen würden. Dann möchten Sie die Unterklasse einfügen. Oder wenn Sie das als Singleton oder Prototyp verwenden wollten. Um ehrlich zu sein, enthält die Konfigurationsdatei alles hartcodiert, bis zu welcher Unterklasse für einen Typ (Schnittstelle) sie während der Kompilierzeit eingefügt werden soll. 

EDIT 

Ein schöner Kommentar von Jose Maria Arranz zu DI

DI erhöht die Kohäsion, indem die Notwendigkeit, die Richtung der Abhängigkeit zu bestimmen und jeglichen Glue-Code zu schreiben, entfällt.

Falsch. Die Richtung der Abhängigkeiten ist in XML-Form oder als Annotation. Ihre Abhängigkeiten werden als XML-Code und Annotationen geschrieben. XML und Anmerkungen sind Quellcode.

DI reduziert die Kopplung, indem alle Ihre Komponenten modular aufgebaut werden (d. H. Austauschbar sind) und über gut definierte Schnittstellen zueinander verfügen.

Falsch. Sie benötigen kein DI-Framework, um einen auf Schnittstellen basierenden modularen Code zu erstellen.

Über austauschbar: Mit einem sehr einfachen .properties-Archiv und Class.forName können Sie festlegen, welche Klassen geändert werden können. Wenn JEDE Klasse Ihres Codes geändert werden kann, ist Java nicht für Sie. Verwenden Sie eine Skriptsprache. Übrigens: Anmerkungen können nicht ohne Neukompilierung geändert werden.

Meiner Meinung nach gibt es einen einzigen Grund für DI-Gerüste: die Reduzierung der Kesselplatte. Mit einem durchdachten Factory-System können Sie das gleiche, besser kontrollierte und vorhersehbare System wie Ihr bevorzugtes DI-Framework ausführen. DI-Frameworks versprechen Code-Reduktion (XML und Annotationen sind ebenfalls Quellcode). Das Problem ist, dass diese Boiler-Plattenreduzierung in sehr einfachen Fällen nur real ist (eine Instanz pro Klasse und ähnliches). Manchmal ist die Auswahl des entsprechenden Service-Objekts in der realen Welt nicht so einfach wie das Zuordnen einer Klasse zu einem Einzelobjekt.

10
Chookoos

Dependency Injection bedeutet Abhängigkeit (eigentlich any-way) für einen Codeteil (z. B. eine Klasse), um auf Abhängigkeiten (andere Codeteile, z. B. andere Klassen, es hängt davon ab) in einem modulare Art und Weise, ohne dass sie hartcodiert sind (damit sie sich ändern oder überschreiben können oder nach Bedarf auch zu einem anderen Zeitpunkt geladen werden können)

(und ps, ja, es wurde zu einem übermäßig gehypten 25 $ -Namen für ein ziemlich einfaches Konzept), mein .25-Cent

8
Nikos M.

Ich weiß, dass es bereits viele Antworten gibt, aber ich fand das sehr hilfreich: http://tutorials.jenkov.com/dependency-injection/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 Instantiierung DataSourceImpl in einen Konstruktor verschoben wird. Der Konstruktor benötigt vier Parameter, dh die vier Werte, die von DataSourceImpl benötigt werden. Obwohl die MyDao-Klasse immer noch von diesen vier Werten abhängt, erfüllt sie diese Abhängigkeiten selbst nicht mehr. Sie werden von der Klasse bereitgestellt, die eine MyDao-Instanz erstellt.

7
Ali Issa

Die häufigsten Antworten sind wenig hilfreich, da sie die Abhängigkeitseinspritzung auf eine Weise definieren, die nicht nützlich ist. Wir stimmen darin überein, dass wir mit "Abhängigkeit" ein vorbestehendes anderes Objekt meinen, das unser Objekt X benötigt. Aber wir sagen nicht, dass wir "Abhängigkeitsinjektion" machen, wenn wir sagen

$foo = Foo->new($bar);

Wir rufen einfach die Übergabeparameter in den Konstruktor auf. Wir machen das seit der Erfindung der Konstrukteure regelmäßig.

"Abhängigkeitsinjektion" wird als eine Art "Inversion der Kontrolle" betrachtet, was bedeutet, dass eine bestimmte Logik aus dem Aufrufer genommen wird. Dies ist nicht der Fall, wenn der Aufrufer Parameter übergibt. Wenn DI also DI wäre, würde DI keine Umkehrung der Steuerung bedeuten.

DI bedeutet, dass zwischen dem Aufrufer und dem Konstruktor, der die Abhängigkeiten verwaltet, eine Zwischenebene vorhanden ist. Ein Makefile ist ein einfaches Beispiel für die Abhängigkeitsinjektion. Der "Aufrufer" ist die Person, die in der Befehlszeile "Make-Leiste" eingibt, und der "Konstruktor" ist der Compiler. Das Makefile gibt an, dass die Leiste von foo abhängt, und es führt ein

gcc -c foo.cpp; gcc -c bar.cpp

bevor Sie ein tun

gcc foo.o bar.o -o bar

Die Person, die "Make Bar" eingibt, muss nicht wissen, dass die Bar von Foo abhängt. Die Abhängigkeit wurde zwischen "make bar" und gcc eingefügt.

Der Hauptzweck der Zwischenstufe ist nicht nur die Übergabe der Abhängigkeiten an den Konstruktor, sondern die Auflistung aller Abhängigkeiten in nur eine Stelle - und das Ausblenden vor dem Codierer (nicht durch den Codierer). .

Normalerweise stellt die Zwischenebene Fabriken für die erstellten Objekte bereit, die eine Rolle bereitstellen müssen, die jeder angeforderte Objekttyp erfüllen muss. Das liegt daran, dass Sie durch eine Zwischenstufe, die die Konstruktionsdetails verbirgt, bereits die von den Fabriken verhängte Abstraktionsstrafe erlitten haben. Sie können also auch Fabriken verwenden.

7
Phil Goetz

Abhängigkeitseinspritzung ist eine mögliche Lösung für das, was allgemein als "Abhängigkeitsverschleierung" bezeichnet werden könnte. Abhängigkeitsverschleierung ist eine Methode, um die "offensichtliche" Natur aus dem Prozess der Bereitstellung einer Abhängigkeit für eine Klasse herauszuholen, die diese erfordert, und daher in gewisser Weise die Bereitstellung dieser Abhängigkeit für die Klasse zu verschleiern. Das ist nicht unbedingt eine schlechte Sache. Durch Verschleiern der Art und Weise, wie eine Abhängigkeit einer Klasse bereitgestellt wird, ist etwas außerhalb der Klasse für die Erzeugung der Abhängigkeit verantwortlich, was bedeutet, dass in verschiedenen Szenarien eine unterschiedliche Implementierung der Abhängigkeit ohne Änderungen an die Klasse geliefert werden kann zur Klasse. Dies ist ideal für den Wechsel zwischen Produktions- und Testmodus (z. B. Verwendung einer 'Mock'-Dienstabhängigkeit).

Leider ist das Schlimme, dass einige Leute davon ausgegangen sind, dass Sie ein spezielles Framework zur Abhängigkeitsverschleierung benötigen und dass Sie irgendwie ein "kleinerer" Programmierer sind, wenn Sie sich dafür entscheiden, kein bestimmtes Framework zu verwenden. Ein anderer, äußerst verstörender Mythos, von dem viele glauben, ist, dass Abhängigkeitsinjektion der einzige Weg ist, eine Abhängigkeitsverschleierung zu erreichen. Dies ist nachweislich und historisch und offensichtlich zu 100% falsch, aber Sie werden Schwierigkeiten haben, einige Leute davon zu überzeugen, dass es Alternativen zur Abhängigkeitsinjektion für Ihre Abhängigkeitsverschleierungsanforderungen gibt.

Programmierer haben die Abhängigkeitsverschleierungsanforderung seit Jahren verstanden, und viele alternative Lösungen haben sich sowohl vor als auch nach dem Einsetzen der Abhängigkeitsinjektion entwickelt. Es gibt Factory-Muster, aber es gibt auch viele Möglichkeiten, ThreadLocal zu verwenden, bei denen keine Injektion in eine bestimmte Instanz erforderlich ist. Die Abhängigkeit wird effektiv in den Thread eingefügt, was den Vorteil hat, dass das Objekt (über statische Getter-Methoden) für any verfügbar gemacht wird class, die es erfordert, ohne dass Anmerkungen zu den Klassen hinzugefügt werden müssen, die dies erfordern, und Sie müssen komplizierte XML-Elemente einrichten, um dies zu ermöglichen. Wenn Ihre Abhängigkeiten für die Persistenz erforderlich sind (JPA/JDO oder was auch immer), können Sie 'transparente Persistenz' viel einfacher und mit Domänenmodell- und Geschäftsmodellklassen erreichen, die ausschließlich aus POJOs bestehen (d. H. Keine Framework-spezifischen/gesperrten Anmerkungen).

6
Volksman

Aus dem Buch ' Fundierter Java-Entwickler: Vitaltechniken von Java 7 und Polyglot-Programmierung

DI ist eine bestimmte Form von IoC, bei der das Finden Ihrer Abhängigkeiten .__ ist. außerhalb der direkten Kontrolle Ihres aktuell ausgeführten Codes.

5
TastyCode

Dependency Injection (DI) ist eine von Design Patterns, die die grundlegende Funktion von OOP verwendet - die Beziehung zwischen einem Objekt und einem anderen Objekt. Während die Vererbung ein Objekt erbt, um ein komplexeres und spezifischeres anderes Objekt auszuführen, erstellt die Beziehung oder Verknüpfung einfach einen Zeiger auf ein anderes Objekt aus einem Objekt mithilfe des Attributs. Die Leistungsfähigkeit von DI ist in Kombination mit anderen Funktionen von OOP sowie Schnittstellen und verstecktem Code . Angenommen, wir haben einen Kunden (Abonnenten) in der Bibliothek, der sich zur Vereinfachung nur ein Buch 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; Eine Art 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 kann der Abonnent dem Buch zugeordnet werden:

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 die eigene Implementierung ausgeblendet 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, die Abhängigkeitsinjektion zu verwenden. Es ist möglich, es mit Singleton usw. zu kombinieren, aber im Grunde ist es nur eine Verknüpfung, die durch das Erstellen eines Attributs eines Objekttyps in einem anderen Objekt realisiert wird .. Die Nützlichkeit besteht nur und nur in der Funktion, dem Code, den wir schreiben sollten immer wieder wird für uns immer nach vorne vorbereitet und getan. Deshalb ist DI so eng mit Inversion of Control (IoC) verbunden, was bedeutet, dass unser Programm ein weiteres laufendes Modul übergibt, das Beans in unseren Code injiziert. (Jedes Objekt, das injiziert werden kann, kann signiert oder als Bean betrachtet werden.) Zum Beispiel in Spring wird dies durch Erstellen und Initialisieren von ApplicationContext container ausgeführt, was bei uns funktioniert. Wir erstellen einfach in unserem Code den Context und rufen die Initialisierung der Beans auf. In diesem Moment wurde die Injektion automatisch durchgeführt.

4
hariprasad

aus Buch Apress.Spring.Persistence.with.Hibernate.Oct.2010

Die Abhängigkeitseinspritzung dient dazu, die Arbeit von .__ zu entkoppeln. Lösung externer Softwarekomponenten aus Ihrem Anwendungsgeschäft logic.Ohne Abhängigkeitsinjektion, die Details, wie eine Komponente Zugriff auf erforderliche Dienste kann mit den Komponenten der Komponente Code. Dies erhöht nicht nur das Fehlerpotenzial, sondern fügt Code .__ hinzu. aufgebläht und vergrößert die Komplexität der Wartung; es verbindet Komponenten enger zusammen, was es schwierig macht, Abhängigkeiten zu ändern, wenn Refactoring oder Testen.

In einfachen Worten ist Abhängigkeitseinspritzung (DI) der Weg, Abhängigkeiten oder enge Kopplung zwischen verschiedenen Objekten zu entfernen. Abhängigkeitseinspritzung gibt jedem Objekt ein zusammenhängendes Verhalten. 

DI ist die Implementierung von IOC von Spring, der sagt: "Rufen Sie uns nicht an, wir rufen Sie an". Die Verwendung des Abhängigkeitspritzenprogrammierers muss nicht mit dem neuen Schlüsselwort erstellt werden. 

Objekte werden einmal in den Spring-Container geladen und dann wiederverwendet, wenn wir sie benötigen, indem wir diese Objekte mit der getBean (String beanName) -Methode aus dem Spring-Container abrufen.

3
Waqas Ahmed

Abhängigkeitsinjektion (DI) ist Teil der Praxis der Abhängigkeitsinversion (DIP), die auch Inversion of Control (IoC) genannt wird. Grundsätzlich müssen Sie DIP ausführen, da Sie Ihren Code modularer und von Einheiten überprüfbarer machen möchten, anstatt nur ein monolithisches System. Sie beginnen also, Teile des Codes zu identifizieren, die von der Klasse getrennt und entfernt werden können. Nun muss die Implementierung der Abstraktion von außerhalb der Klasse eingefügt werden. Normalerweise kann dies über den Konstruktor erfolgen. Sie erstellen also einen Konstruktor, der die Abstraktion als Parameter akzeptiert, und dies wird als Abhängigkeitsinjektion (über den Konstruktor) bezeichnet. Weitere Informationen zu DIP-, DI- und IoC-Containern finden Sie Here

3

Abhängigkeitseinspritzung ist das Herzstück des mit Spring Framework verwandten Konzepts. Wenn das Rahmenwerk eines jeden Projektfrühlinges erstellt wird, kann dies eine wichtige Rolle spielen, und hier kommt die Abhängigkeitseinspritzung in Pitcher.

Angenommen, Sie haben in Java zwei verschiedene Klassen als Klasse A und Klasse B erstellt, und was auch immer die Funktion in Klasse B zur Verfügung steht, die Sie in Klasse A verwenden möchten, kann zu diesem Zeitpunkt Abhängigkeitsinjektion verwendet werden, wo dies möglich ist Kistenobjekt einer Klasse in einer anderen Klasse. Auf dieselbe Weise können Sie eine ganze Klasse in eine andere Klasse einfügen, um sie zugänglich zu machen. Durch diese Art und Weise kann die Abhängigkeit überwunden werden.

ABHÄNGIGKEITSINJEKTION IS EINFACH BEIM KLEBEN VON ZWEI KLASSEN UND AT DER GLEICHEN ZEIT, DIE SIE SEPARAT HALTEN.

3
mohit sarsar

Ich würde eine etwas andere, kurze und genaue Definition dessen vorschlagen, was Abhängigkeitsinjektion ist, und zwar auf das primäre Ziel und nicht auf die technischen Mittel (im Anschluss an hier ):

Abhängigkeitseinspritzung ist der Vorgang des Erstellens des statischen statuslosen Diagramm von Service-Objekten, bei denen jeder Service durch seine .__ parametrisiert wird. Abhängigkeiten.

Die Objekte, die wir in unseren Anwendungen erstellen (unabhängig davon, ob wir Java, C # oder eine andere objektorientierte Sprache verwenden) fallen normalerweise in eine von zwei Kategorien: stateless, statische und globale "Service-Objekte" (Module) sowie Stateful, Dynamic und Local "Datenobjekte".

Das Moduldiagramm - das Diagramm der Serviceobjekte - wird normalerweise beim Start der Anwendung erstellt. Dies kann mit einem Container wie Spring geschehen, kann aber auch manuell erfolgen, indem Parameter an Objektkonstruktoren übergeben werden. Beide Möglichkeiten haben ihre Vor- und Nachteile, aber es ist definitiv nicht notwendig, DI in Ihrer Anwendung zu verwenden.

Eine Voraussetzung ist, dass die Dienste durch ihre Abhängigkeiten parametrisiert werden müssen. Was dies genau bedeutet, hängt von der Sprache und dem Ansatz eines bestimmten Systems ab. Normalerweise hat dies die Form von Konstruktorparametern, die Verwendung von Setters ist jedoch auch eine Option. Dies bedeutet auch, dass die Abhängigkeiten eines Dienstes (beim Aufrufen einer Dienstmethode) für die Benutzer des Dienstes verborgen sind.

Wann verwenden? Ich würde sagen, wann immer die Anwendung groß genug ist, um die Logik in separate Module einzukapseln, wobei ein Abhängigkeitsgraph zwischen den Modulen einen Gewinn an Lesbarkeit und Erkundbarkeit des Codes ergibt.

2
adamw

Abhängigkeitsinjektion ist die Praxis, entkoppelte Komponentenagnostiker von einigen ihrer Abhängigkeiten zu machen, dies folgt der SOLID -Richtlinie, die besagt

Prinzip der Inversion der Abhängigkeit: man sollte "auf Abstraktionen angewiesen sein, nicht Konkretionen.

Die bessere Implementierung von Dependency Injection ist das Kompositionswurzel-Entwurfsmuster, da Ihre Komponenten vom Abhängigkeitsinjektionscontainer entkoppelt werden können.

Ich empfehle diesen großartigen Artikel über Composition Root http://blog.ploeh.dk/2011/07/28/CompositionRoot/ , Geschrieben von Mark Seemann

hier sind wesentliche Punkte aus diesem Artikel:

Eine Kompositionswurzel ist ein (vorzugsweise) eindeutiger Ort in einer Anwendung wo Module zusammengesetzt sind.

...

Nur Anwendungen sollten Kompositionswurzeln haben. Bibliotheken und Frameworks sollten nicht.

...

Ein DI-Container sollte nur von der Kompositionswurzel aus referenziert werden. Alle anderen Module sollten keinen Bezug zum Container haben.

Die Dokumentation von Di-Ninja, einem Abhängigkeitsinjektions-Framework, ist ein sehr gutes Beispiel, um zu zeigen, wie die Prinzipien des Kompositionswurzels und der Abhängigkeitsinjektion funktionieren https://github.com/di-ninja/di-ninja Wie ich weiß, ist das einzige DiC in Javascript, das das Composition-Root-Entwurfsmuster implementiert.

1
Jo Takion

Aus Christoffer Noring, Pablo Deelemans Buch "Learning Angular - Second Edition":

"Während unsere Anwendungen wachsen und sich weiterentwickeln, werden alle unsere Code-Entitäten intern Instanzen anderer Objekte erfordern, die besser als Abhängigkeiten in der Welt des Software-Engineerings bekannt sind. Die Weitergabe solcher Abhängigkeiten an den abhängigen Client wird als Injektion bezeichnet. Dies beinhaltet auch die Teilnahme einer anderen Code-Entität namens Injektor.Der Injektor übernimmt die Verantwortung für das Instanziieren und Bootstrapping der erforderlichen Abhängigkeiten, so dass sie ab dem Moment, in dem sie erfolgreich in den Client injiziert werden, einsatzbereit sind Der Client weiß nicht, wie er seine eigenen Abhängigkeiten instanziieren kann, und er kennt nur die Schnittstelle, die er implementiert, um sie zu nutzen. "

1
H S Progr

Abhängigkeitsinjektion ist eine Art Implementierung des " Inversion of Control " - Prinzips, auf dem Frameworks basieren.

Frameworks Wie in "Design Pattern" von GoF angegeben, sind Klassen, die die Hauptsteuerungslogik implementieren und den Entwickler dazu auffordern, dies zu tun. Auf diese Weise erkennen Frameworks das Prinzip der Umkehrung des Steuerelements.

Dieses IoC-Prinzip ist eine Methode zur Implementierung als Technik und nicht als Klassenhierarchie. Es handelt sich dabei lediglich um Abhängigkeitsinjektion.

DIbesteht hauptsächlich aus dem Delegieren der Zuordnung von Klasseninstanzen und der Typreferenz auf diese Instanzen an eine externe "Entität": ein Objekt, eine statische Klasse, eine Komponente, ein Framework usw. 

Klasseninstanzen sind die "Abhängigkeiten", die externe Bindung der aufrufenden Komponente mit der Klasseninstanz durch die Referenz ist "injection".

Offensichtlich können Sie diese Technik in vielerlei Hinsicht aus Sicht von OOP implementieren, siehe zum Beispiel Konstruktorinjektion, Setterinjektion, Schnittstelleninjektion.

Das Delegieren eines Dritten zum Ausführen eines Abgleichs einer Referenz mit einem Objekt ist sehr nützlich, wenn Sie eine Komponente, die einige Dienste benötigt, von der gleichen Dienstimplementierung vollständig trennen möchten. 

Auf diese Weise können Sie sich beim Entwerfen von Komponenten ausschließlich auf ihre Architektur und ihre spezifische Logik konzentrieren und auf Schnittstellen für die Zusammenarbeit mit anderen Objekten vertrauen, ohne sich um jegliche Art von Implementierungsänderungen der verwendeten Objekte/Services kümmern zu müssen, auch wenn dasselbe Objekt, das Sie verwenden wird komplett ersetzt (natürlich unter Berücksichtigung der Schnittstelle).

1
Ciro Corvino

Jede nicht-triviale Anwendung besteht aus zwei oder mehr Klassen, die zusammenarbeiten, um Geschäftslogik auszuführen. Traditionell ist jedes Objekt dafür verantwortlich, seine eigenen Verweise auf die Objekte zu erhalten, mit denen es zusammenarbeitet (seine Abhängigkeiten). Beim Anwenden von DI werden die Objekte zum Zeitpunkt der Erstellung von einer externen Entität abhängig gemacht, die jedes Objekt im System koordiniert. Mit anderen Worten, Abhängigkeiten werden in Objekte eingefügt.

Weitere Details finden Sie unter Linkbeschreibung hier eingeben

0
Hisham Javed

DI ist, wie reale Objekte tatsächlich miteinander interagieren, ohne dass ein Objekt für die Existenz eines anderen Objekts verantwortlich ist. Objekte sollten gleich behandelt werden. Sie sind alle Objekte. Niemand sollte sich wie ein Schöpfer verhalten. So werden Sie Ihren Objekten gerecht.

Einfaches Beispiel

wenn Sie einen Arzt brauchen, suchen Sie einfach einen (vorhandenen). Sie werden nicht daran denken, einen Arzt von Grund auf zu erstellen, um Ihnen zu helfen. Er existiert bereits und kann Ihnen oder anderen Objekten dienen. Er hat das Recht zu existieren, unabhängig davon, ob Sie (ein einzelner Gegenstand) ihn brauchen oder nicht, weil es sein Ziel ist, einen oder mehrere Gegenstände zu bedienen. Wer für seine Existenz entschieden hat, ist der allmächtige Gott, keine natürliche Auslese. Daher besteht ein Vorteil von DI darin, zu vermeiden, dass unnötige, redundante Objekte während der Lebensdauer Ihres Universums (d. H. Anwendung) ohne Zweck leben.

0
Shadi Namrouti