Ich finde, dass meine Konstruktoren so aussehen:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
mit ständig wachsender Parameterliste. Da "Container" mein Abhängigkeitsinjektionscontainer ist, warum kann ich das nicht einfach so machen:
public MyClass(Container con)
für jede Klasse? Was sind die Nachteile? Wenn ich das mache, fühlt es sich an, als würde ich eine verherrlichte Statik verwenden. Bitte teilen Sie Ihre Gedanken zu IoC und Dependency Injection Madness mit.
c#
java
dependency-injection
inversion-of-control
ioc-container
JP Richardson
quelle
quelle
Antworten:
Sie haben Recht, wenn Sie den Container als Service Locator verwenden, handelt es sich mehr oder weniger um eine verherrlichte statische Fabrik. Aus vielen Gründen halte ich dies für ein Anti-Muster .
Einer der wunderbaren Vorteile von Constructor Injection besteht darin, dass Verstöße gegen das Prinzip der Einzelverantwortung offensichtlich werden.
In diesem Fall ist es an der Zeit, die Facade Services zu überarbeiten . Kurz gesagt, erstellen Sie eine neue, grobkörnigere Schnittstelle, die die Interaktion zwischen einigen oder allen feinkörnigen Abhängigkeiten verbirgt, die Sie derzeit benötigen.
quelle
Ich denke nicht, dass Ihre Klassenkonstruktoren einen Verweis auf Ihre IOC-Containerperiode haben sollten. Dies stellt eine unnötige Abhängigkeit zwischen Ihrer Klasse und dem Container dar (die Art der Abhängigkeit, die das IOC zu vermeiden versucht!).
quelle
MyClass myClass = new MyClass(IDependency1 interface1, IDependency2 interface2)
(Schnittstellenparameter). Dies hat nichts mit dem Beitrag von @ derivation zu tun, den ich so interpretiere, dass ein Abhängigkeitsinjektionscontainer sich nicht in seine Objekte injizieren sollte, dhMyClass myClass = new MyClass(this)
Die Schwierigkeit, die Parameter zu übergeben, ist nicht das Problem. Das Problem ist, dass Ihre Klasse zu viel tut und mehr aufgeschlüsselt werden sollte.
Die Abhängigkeitsinjektion kann als Frühwarnung für zu große Klassen dienen, insbesondere aufgrund der zunehmenden Schmerzen beim Übergeben aller Abhängigkeiten.
quelle
Ich stieß auf eine ähnliche Frage zur konstruktorbasierten Abhängigkeitsinjektion und wie komplex es wurde, alle Abhängigkeiten zu übergeben.
Ein Ansatz, den ich in der Vergangenheit verwendet habe, ist die Verwendung des Anwendungsfassadenmusters unter Verwendung einer Serviceschicht. Dies hätte eine grobe API. Wenn dieser Dienst von Repositorys abhängt, wird eine Setter-Injection der privaten Eigenschaften verwendet. Dies erfordert das Erstellen einer abstrakten Factory und das Verschieben der Logik zum Erstellen der Repositorys in eine Factory.
Detaillierten Code mit Erläuterungen finden Sie hier
Best Practices für IoC in komplexen Serviceschichten
quelle
Ich habe diesen ganzen Thread zweimal gelesen und ich denke, die Leute antworten mit dem, was sie wissen, nicht mit dem, was gefragt wird.
JPs ursprüngliche Frage sieht so aus, als würde er Objekte konstruieren, indem er einen Resolver und dann eine Reihe von Klassen sendet. Wir gehen jedoch davon aus, dass diese Klassen / Objekte selbst Dienste sind, die für die Injektion reif sind. Was ist, wenn sie nicht sind?
JP, wenn Sie DI nutzen möchten und den Ruhm des Mischens von Injektion mit Kontextdaten wünschen, spricht keines dieser Muster (oder angebliche "Anti-Muster") dies speziell an. Es läuft tatsächlich darauf hinaus, ein Paket zu verwenden, das Sie bei einem solchen Unterfangen unterstützt.
... dieses Format wird selten unterstützt. Ich glaube, dass die Schwierigkeit, eine solche Unterstützung zu programmieren, zusätzlich zu der miserablen Leistung, die mit der Implementierung verbunden wäre, sie für Open Source-Entwickler unattraktiv macht.
Aber es sollte getan werden, weil ich in der Lage sein sollte, eine Factory für MyClass zu erstellen und zu registrieren, und diese Factory sollte in der Lage sein, Daten / Eingaben zu empfangen, die nicht nur zum Zweck des Bestehens zu einem "Service" werden Daten. Wenn es bei "Anti-Pattern" um negative Konsequenzen geht, ist es sicherlich negativ, die Existenz künstlicher Servicetypen für die Übergabe von Daten / Modellen zu erzwingen (genau wie Sie das Gefühl haben, Ihre Klassen in einen Container zu packen. Der gleiche Instinkt gilt).
Es gibt jedoch Rahmenbedingungen, die helfen können, auch wenn sie etwas hässlich aussehen. Zum Beispiel Ninject:
Erstellen einer Instanz mit Ninject mit zusätzlichen Parametern im Konstruktor
Das ist für .NET, beliebt und nirgends so sauber wie es sein sollte, aber ich bin mir sicher, dass es in jeder Sprache, die Sie verwenden, etwas gibt.
quelle
Das Injizieren des Containers ist eine Abkürzung, die Sie letztendlich bereuen werden.
Eine Überinjektion ist nicht das Problem, sondern in der Regel ein Symptom für andere strukturelle Mängel, insbesondere für die Trennung von Bedenken. Dies ist kein Problem, kann aber viele Ursachen haben, und was es so schwierig macht, dies zu beheben, ist, dass Sie sich manchmal gleichzeitig mit allen befassen müssen (denken Sie daran, Spaghetti zu entwirren).
Hier ist eine unvollständige Liste der Dinge, auf die Sie achten müssen
Schlechtes Domain-Design (aggregierte Roots… usw.)
Schlechte Trennung von Bedenken (Servicezusammensetzung, Befehle, Abfragen) Siehe CQRS und Event Sourcing.
ODER Mapper (seien Sie vorsichtig, diese Dinge können Sie in Schwierigkeiten bringen)
Modelle und andere DTOs anzeigen (Niemals eines wiederverwenden und versuchen, sie auf ein Minimum zu beschränken !!!!)
quelle
Problem :
1) Konstruktor mit ständig wachsender Parameterliste.
2) Wenn eine Klasse geerbt wird (Beispiel :), führt eine
RepositoryBase
Änderung der Konstruktorsignatur zu einer Änderung der abgeleiteten Klassen.Lösung 1
Pass
IoC Container
zum KonstruktorWarum
Warum nicht
Lösung 2
Erstellen Sie eine Klasse, die alle Dienste gruppiert und an den Konstruktor übergibt
Abgeleitete Klasse
Warum
A
abhängt, werden diese Informationen gemäß der Konvention gesammeltA.Dependency
Warum nicht
X.Dependency
separat registrieren )IoC Container
Lösung 2 ist jedoch nur eine rohe, wenn es solide Argumente dagegen gibt, wäre ein beschreibender Kommentar willkommen
quelle
Dies ist der Ansatz, den ich benutze
Hier ist ein grober Ansatz, wie die Injektionen durchgeführt und der Konstruktor nach dem Injizieren von Werten ausgeführt wird. Dies ist ein voll funktionsfähiges Programm.
Ich arbeite gerade an einem Hobbyprojekt, das so funktioniert folgt https://github.com/Jokine/ToolProject/tree/Core
quelle
Welches Abhängigkeitsinjektionsframework verwenden Sie? Haben Sie versucht, stattdessen eine Setter-basierte Injektion zu verwenden?
Der Vorteil der konstruktorbasierten Injektion besteht darin, dass sie für Java-Programmierer, die keine DI-Frameworks verwenden, natürlich aussieht. Sie benötigen 5 Dinge, um eine Klasse zu initialisieren, dann haben Sie 5 Argumente für Ihren Konstruktor. Der Nachteil ist, was Sie bemerkt haben, es wird unhandlich, wenn Sie viele Abhängigkeiten haben.
Mit Spring können Sie die erforderlichen Werte stattdessen mit Setzern übergeben und @required-Annotationen verwenden, um zu erzwingen, dass sie injiziert werden. Der Nachteil ist, dass Sie den Initialisierungscode vom Konstruktor auf eine andere Methode verschieben und Spring aufrufen müssen, nachdem alle Abhängigkeiten durch Markieren mit @PostConstruct eingefügt wurden. Ich bin mir bei anderen Frameworks nicht sicher, aber ich gehe davon aus, dass sie etwas Ähnliches tun.
Beides funktioniert, es ist eine Frage der Präferenz.
quelle