Erwägen:
public class CtorInjectionExample
{
public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
{
this._someRepository = SomeRepositoryIn;
this._otherRepository = OtherRepositoryIn;
}
public void SomeMethod()
{
//use this._someRepository
}
public void OtherMethod()
{
//use this._otherRepository
}
}
gegen:
public class MethodInjectionExample
{
public MethodInjectionExample()
{
}
public void SomeMethod(ISomeRepository SomeRepositoryIn)
{
//use SomeRepositoryIn
}
public void OtherMethod(IOtherRepository OtherRepositoryIn)
{
//use OtherRepositoryIn
}
}
Während die Ctor-Injektion die Erweiterung erschwert (jeder Code, der den Ctor aufruft, muss aktualisiert werden, wenn neue Abhängigkeiten hinzugefügt werden), und die Methodenebeneninjektion scheint stärker von der Klassenebenenabhängigkeit abgekapselt zu bleiben, und ich kann keine anderen Argumente für / gegen diese Ansätze finden .
Gibt es einen endgültigen Ansatz für die Injektion?
(Hinweis: Ich habe nach Informationen dazu gesucht und versucht, diese Frage objektiv zu machen.)
Antworten:
Es hängt davon ab, ob das injizierte Objekt von mehr als einer Methode in der Klasse verwendet wird und ob das Injizieren bei jeder Methode keinen Sinn ergibt. Sie müssen die Abhängigkeiten für jeden Methodenaufruf auflösen, und ob die Abhängigkeit nur von verwendet wird Eine Methode, die in den Konstruktor eingefügt wird, ist nicht gut, aber da Sie Ressourcen zuweisen, die niemals verwendet werden könnten.
quelle
Zunächst einmal: "Jeder Code, der den ctor aufruft, muss aktualisiert werden, wenn neue Abhängigkeiten hinzugefügt werden." Um klar zu sein, wenn Sie eine Abhängigkeitsinjektion durchführen und Code für ein Objekt mit Abhängigkeiten new () aufruft, machen Sie es falsch .
Ihr DI-Container sollte in der Lage sein, alle relevanten Abhängigkeiten einzuschleusen, sodass Sie sich keine Gedanken über das Ändern der Konstruktorsignatur machen müssen, damit dieses Argument nicht wirklich zutrifft.
Was die Idee der Injektion pro Methode im Vergleich zur Injektion pro Klasse betrifft, gibt es zwei Hauptprobleme bei der Injektion pro Methode.
Ein Problem ist, dass die Methoden Ihrer Klasse Abhängigkeiten gemeinsam nutzen sollten. Auf diese Weise können Sie sicherstellen, dass Ihre Klassen effektiv getrennt sind. Wenn Sie eine Klasse mit einer großen Anzahl von Abhängigkeiten (wahrscheinlich mehr als 4-5) sehen, ist diese Klasse ein Hauptkandidat zum Refactoring in zwei Klassen.
Das nächste Problem ist, dass Sie die Abhängigkeiten pro Methode an den Methodenaufruf übergeben müssen, um sie zu "injizieren". Dies bedeutet, dass Sie die Abhängigkeiten vor dem Methodenaufruf auflösen müssen, sodass Sie wahrscheinlich eine Menge Code wie den folgenden erhalten:
Angenommen, Sie rufen diese Methode an 10 Stellen in Ihrer Anwendung auf: Sie haben 10 dieser Snippets. Angenommen, Sie müssen DoStuff () eine weitere Abhängigkeit hinzufügen: Sie müssen dieses Snippet zehnmal ändern (oder es in eine Methode einschließen. In diesem Fall replizieren Sie das DI-Verhalten nur manuell, was eine Verschwendung ist von Zeit).
Was Sie also im Grunde dort getan haben, ist, Ihre DI-nutzenden Klassen auf ihren eigenen DI-Container aufmerksam zu machen, was eine grundsätzlich schlechte Idee ist , da dies sehr schnell zu einem klobigen Design führt, das schwer zu warten ist.
Vergleichen Sie das mit Konstruktorinjektion; Bei der Konstruktorinjektion sind Sie nicht an einen bestimmten DI-Container gebunden, und Sie sind niemals direkt dafür verantwortlich, die Abhängigkeiten Ihrer Klassen zu erfüllen, sodass die Wartung ziemlich problemlos vonstatten geht.
Es klingt für mich so, als würden Sie versuchen, IoC auf eine Klasse anzuwenden, die eine Reihe von nicht verwandten Hilfsmethoden enthält, während Sie die Hilfsklasse je nach Verwendung besser in eine Reihe von Serviceklassen aufteilen und dann die Hilfsmethode zum Delegieren der Klasse verwenden sollten Anrufe. Dies ist immer noch kein großartiger Ansatz (Helfer, die mit Methoden klassifiziert sind, die etwas Komplexeres tun als nur mit den Argumenten umzugehen, die an sie übergeben werden, sind im Allgemeinen nur schlecht geschriebene Serviceklassen), aber er wird Ihr Design zumindest ein wenig sauberer halten .
(NB Ich habe den von Ihnen vorgeschlagenen Ansatz befolgt und es war eine sehr schlechte Idee, die ich seitdem nicht wiederholt habe. Es stellte sich heraus, dass ich versuchte, Klassen zu trennen, die wirklich nicht getrennt werden mussten, und endete mit einer Reihe von Schnittstellen, bei denen jeder Methodenaufruf eine nahezu feste Auswahl anderer Schnittstellen erforderte. Es war ein Albtraum, dies beizubehalten.)
quelle
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."
Wenn Sie eine Methode für eine Klasse einem Komponententest unterziehen, müssen Sie sie instanziieren, oder verwenden Sie DI, um Ihren getesteten Code zu instanziieren?"any code calling the ctor will need updating"
, dass mein Produktionscode die ctors nicht aufruft. Aus diesen Gründen.Es gibt verschiedene Arten der Umkehrung der Kontrolle , und Ihre Frage schlägt nur zwei vor (Sie können auch factory verwenden, um die Abhängigkeit zu injizieren).
Die Antwort lautet: Es kommt auf die Bedürfnisse an. Manchmal ist es besser, eine Art und eine andere Art zu verwenden.
Ich persönlich mag Konstruktor-Injektoren, da der Konstruktor da ist, um das Objekt vollständig zu initialisieren. Wenn Sie später einen Setter aufrufen müssen, ist das Objekt nicht vollständig aufgebaut.
quelle
Sie haben den verpasst, der zumindest für mich die flexibelste Eigenschaftsinjektion ist. Ich benutze Castle / Windsor und füge meiner Klasse lediglich eine neue Auto-Eigenschaft hinzu. Ich erhalte das injizierte Objekt ohne Probleme und ohne irgendwelche Schnittstellen zu beschädigen.
quelle