14 Stimmen

DI-Framework: Wie lässt sich vermeiden, dass injizierte Abhängigkeiten ständig in der Kette nach oben weitergereicht werden, ohne dass ein Service-Locator verwendet wird (insbesondere mit Ninject)

Ich brauche ein wenig mehr Hilfe, um zu verstehen, wie ein DI-Framework wie Ninject über die Grundlagen hinausgeht.

Nehmen Sie die Ninject-Probe:

class Samurai {
private IWeapon _weapon;

    [Inject]
    public Samurai(IWeapon weapon) {
      _weapon = weapon;
    }

    public void Attack(string target) {
      _weapon.Hit(target);
    }
 }

Ohne ein DI-Framework (d.h. die [Inject]-Referenzen oben) würde eine referenzierende Klasse etwa so aussehen:

class Program {
   public static void Main() { 
    Samurai warrior1 = new Samurai(new Shuriken());
    Samurai warrior2 = new Samurai(new Sword());
    warrior1.Attack("the evildoers");
    warrior2.Attack("the evildoers");
  }
}

...wo du alles neu machst. Ja, Sie haben die Abhängigkeit in Samurai entfernt, aber jetzt haben Sie eine Abhängigkeit einen Schritt weiter oben in der Kette. Ganz einfach.

Mit Ninject müssen Sie nicht mehr alles neu einrichten:

class Program {
  public static void Main() {
    IKernel kernel = new StandardKernel(new WarriorModule());
    Samurai warrior = kernel.Get<Samurai>();
    warrior.Attack("the evildoers");
  }
}

JEDOCH, das ist mein Bereich der Verwirrung: ohne eine Art von Service-Locater zu machen, um sich um effizientes Newing up der anwendbaren Kernel und Modul (d.h. .IoC.TypeResolver.Get<>()) zu kümmern, was ist a) der beste Weg, um nicht zu haben, um neue Kernel überall (Service-Locater Referenzen überall? ), und b) was noch wichtiger ist, wenn man eine lange Kette mit Abhängigkeiten mit eigenen Abhängigkeiten hat, dann treibt man es auf die Spitze, indem man Injektionen den ganzen Weg nach oben weitergibt, was sicher ein ernsthaftes Anti-Pattern ist (ein Freund nannte es "hot-potato dependency injection" Anti-Pattern).

Mit anderen Worten, ich dachte, dass ein Teil der Magie des DI-Frameworks darin besteht, dass Sie nicht ständig Abhängigkeiten in der gesamten Kette einfügen müssen (d.h. Ihr erster Verweis enthält 10 Parameter in seinem Konstruktor, von denen keiner etwas mit irgendetwas zu tun hat, bis er viel weiter in der Kette ist) - wo ist die Magie oder die Lösung für meine Verwirrung, damit Abhängigkeiten nicht ständig in der Kette nach oben referenziert werden oder Service-Locator-Referenzen überall verteilt werden.

Weiter verwirrt das Wasser für mich ist, wenn mit einem DI-Framework, was ist der beste Weg, um ein Szenario zu behandeln, wo eine referenzierte Klasse eine IList benötigt, die in der Regel in den Konstruktor (d.h. neue ReferencedClass(myList)) gesetzt werden würde, wie das, anders als in einfachen Fällen wie eine String-Datenbank-Verbindung-String, nicht fliegen. Machen Sie einfach eine Eigenschaft und setzen Sie es nach dem Newing es up/DI Framework Service lokalisieren? I.e.

var referencedClass = IoC.Get<IReferencedClass>();
referencedClass.MyList = myList;

Alles in allem ist dies ein Beitrag, für den ich mich wahrscheinlich schämen werde, nachdem ich ihn bekommen habe, aber im Moment habe ich meinen Kopf zu oft gegen die Wand geschlagen, um den besten Ansatz zu finden.

3voto

Eric King Punkte 11152

Was das Problem der "heißen Kartoffel" in der Abhängigkeit betrifft, so muss dies nicht passieren. Das Dependency Injection Framework übernimmt dies für Sie.

Wenn beispielsweise Klasse1 eine Abhängigkeit von Klasse2 und Klasse2 eine Abhängigkeit von Klasse3 hat, können Sie nicht eine Klasse3 in Klasse1 injizieren müssen, um die Abhängigkeit von Klasse2 zu berücksichtigen. Der Kernel wird die Abhängigkeitskette für Sie durchlaufen und die nachgelagerten Abhängigkeiten automatisch auflösen (sofern alle betroffenen Klassen im Kernel registriert wurden), wenn Sie eine Klasse1 anfordern.

Klasse1 hängt ab von Klasse2 hängt ab von Klasse3

Der Class1-Konstruktor braucht Class3 überhaupt nicht zu erwähnen.

Was den zweiten Punkt anbelangt, so hängt es von den Rahmenbedingungen ab, ob und wie diese berücksichtigt werden. Bei Ninject kann man, glaube ich, die Bind().To().WithConstructorArgument() Syntax, um das neue Listenelement an den Konstruktor zu übergeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X