[dependency-injection] Warum benutzt man die Abhängigkeitsinjektion?



Answers

Ich denke oft, dass Leute verwirrt sind über den Unterschied zwischen der Abhängigkeitsinjektion und einem Abhängigkeitsinjektions- Framework (oder einem Container, wie es oft genannt wird).

Abhängigkeitsinjektion ist ein sehr einfaches Konzept. Anstelle dieses Codes:

public class A {
  private B b;

  public A() {
    this.b = new B(); // A *depends on* B
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  A a = new A();
  a.DoSomeStuff();
}

Du schreibst Code wie folgt:

public class A {
  private B b;

  public A(B b) { // A now takes its dependencies as arguments
    this.b = b; // look ma, no "new"!
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  B b = new B(); // B is constructed here instead
  A a = new A(b);
  a.DoSomeStuff();
}

Und das ist es. Ernst. Das gibt Ihnen eine Menge Vorteile. Zwei wichtige sind die Fähigkeit, Funktionalität von einem zentralen Ort aus zu steuern (die Main() -Funktion), anstatt sie in Ihrem gesamten Programm zu verteilen, und die Möglichkeit, jede Klasse isoliert zu testen (weil Sie Mocks oder andere gefälschte Objekte weitergeben können) sein Konstruktor anstelle eines realen Wertes).

Der Nachteil ist natürlich, dass Sie jetzt eine Megafunktion haben, die alle Klassen Ihres Programms kennt. Damit können DI-Frameworks helfen. Aber wenn Sie Probleme haben zu verstehen, warum dieser Ansatz wertvoll ist, würde ich Ihnen empfehlen, zuerst mit der manuellen Abhängigkeitsinjektion zu beginnen, damit Sie besser einschätzen können, was die verschiedenen Frameworks da draußen für Sie tun können.

Question

Ich versuche, Abhängigkeitsinjektionen (DI) zu verstehen, und noch einmal habe ich versagt. Es scheint einfach albern. Mein Code ist nie ein Chaos; Ich schreibe kaum virtuelle Funktionen und Interfaces (obwohl ich es einmal bei einem Blue Moon mache) und meine gesamte Konfiguration wird auf magische Weise in eine Klasse unter Verwendung von json.net serialisiert (manchmal unter Verwendung eines XML-Serialisierers).

Ich verstehe nicht ganz, welches Problem es löst. Es sieht so aus, als könnte man sagen: "hi. Wenn Sie diese Funktion aufrufen, geben Sie ein Objekt dieses Typs zurück und verwenden diese Parameter / Daten."
Aber ... warum sollte ich das jemals benutzen? Hinweis: Ich habe noch nie ein object benötigt, aber ich verstehe, wofür es ist.

Was sind reale Situationen beim Erstellen einer Website oder Desktop-Anwendung, wo man DI verwenden würde? Ich kann Fälle leicht herausfinden, warum jemand vielleicht Schnittstellen / virtuelle Funktionen in einem Spiel verwenden möchte, aber es ist extrem selten (selten genug, dass ich mich an eine einzelne Instanz nicht erinnern kann), um das in Nicht-Spiel-Code zu verwenden.




Ich denke, die klassische Antwort ist, eine entkoppelte Anwendung zu erstellen, die nicht weiß, welche Implementierung zur Laufzeit verwendet wird.

Wir sind beispielsweise ein zentraler Zahlungsdienstleister und arbeiten mit vielen Zahlungsanbietern auf der ganzen Welt zusammen. Wenn jedoch eine Anfrage gestellt wird, habe ich keine Ahnung, welchen Zahlungsprozessor ich anrufen werde. Ich könnte eine Klasse mit einer Tonne von Switch-Fällen programmieren, zum Beispiel:

class PaymentProcessor{

    private String type;

    public PaymentProcessor(String type){
        this.type = type;
    }

    public void authorize(){
        if (type.equals(Consts.PAYPAL)){
            // Do this;
        }
        else if(type.equals(Consts.OTHER_PROCESSOR)){
            // Do that;
        }
    }
}

Stellen Sie sich nun vor, dass Sie diesen Code in einer einzigen Klasse verwalten müssen, da er nicht ordnungsgemäß entkoppelt ist. Sie können sich vorstellen, dass Sie für jeden neuen Prozessor, den Sie unterstützen, einen neuen if // switch-Fall erstellen müssen Jede Methode wird jedoch nur komplizierter, wenn Sie Dependency Injection (oder Inversion of Control - wie es manchmal genannt wird, was bedeutet, dass derjenige, der die Ausführung des Programms steuert, nur zur Laufzeit bekannt ist, und keine Komplikation), können Sie etwas erreichen sehr ordentlich und pflegeleicht.

class PaypalProcessor implements PaymentProcessor{

    public void authorize(){
        // Do PayPal authorization
    }
}

class OtherProcessor implements PaymentProcessor{

    public void authorize(){
        // Do other processor authorization
    }
}

class PaymentFactory{

    public static PaymentProcessor create(String type){

        switch(type){
            case Consts.PAYPAL;
                return new PaypalProcessor();

            case Consts.OTHER_PROCESSOR;
                return new OtherProcessor();
        }
    }
}

interface PaymentProcessor{
    void authorize();
}

** Der Code wird nicht kompiliert, ich weiß :)






Links