Akzeptable Platzierung der Zusammensetzungswurzel unter Verwendung von Abhängigkeitsinjektion (DI) und Inversion von Kontrollbehältern (IoC)

8

Ich habe in mehreren Quellen gelesen, darunter in Mark Seemanns 'Ploeh'-Blog, wie die richtige Platzierung des Kompositionsstamms eines IoC-Containers so nah wie möglich am Einstiegspunkt einer Anwendung liegt.

In der .NET-Welt werden diese Anwendungen häufig als Webprojekte, WPF-Projekte, Konsolenanwendungen und Dinge mit einer typischen Benutzeroberfläche (sprich: keine Bibliotheksprojekte) angesehen.

Verstößt es wirklich gegen diesen weisen Rat, die Kompositionswurzel am Einstiegspunkt eines Bibliotheksprojekts zu platzieren, wenn sie den logischen Einstiegspunkt einer Gruppe von Bibliotheksprojekten darstellt, und der Kunde einer Projektgruppe wie dieser ist die Arbeit eines anderen , dessen Autor das Kompositionsstammverzeichnis nicht zu seinem Projekt hinzufügen kann oder will (sogar ein UI-Projekt oder ein weiteres Bibliotheksprojekt)?

Ich bin mit Ninject als IoC-Container-Implementierung vertraut, aber ich stelle mir vor, dass viele andere auf die gleiche Weise arbeiten, indem sie nach einem Modul suchen können, das alle erforderlichen Bindungskonfigurationen enthält. Dies bedeutet, dass ich ein Bindungsmodul in ein eigenes Bibliotheksprojekt einfügen könnte, um es mit der Ausgabe meines Hauptbibliotheksprojekts zu kompilieren. Wenn der Client die Konfiguration ändern wollte (in meinem Fall ein unwahrscheinliches Szenario), könnte er eine Ersatz-DLL einfügen, um die zu ersetzen Bibliothek mit dem Bindungsmodul.

Dies scheint zu vermeiden, dass die häufigsten Clients überhaupt mit Abhängigkeitsinjektion und Kompositionswurzeln zu tun haben, und würde die sauberste API für die Bibliotheksprojektgruppe ergeben.

Dies scheint jedoch angesichts der konventionellen Weisheit in dieser Frage zu fliegen. Ist es nur so, dass die meisten Ratschläge davon ausgehen, dass der Entwickler auch eine gewisse Koordination mit der Entwicklung der UI-Projekte hat, und nicht mein Fall, in dem ich nur Bibliotheken entwickle, die andere verwenden können?

Jeff
quelle

Antworten:

2

Ihr Bindungsmodul-Ansatz ist die beste Lösung. Wenn es unwahrscheinlich ist, dass der Client die Konfiguration ändert, ist die Verwendung von DI für Ihre Bibliothek fraglich.

Wenn Sie eine Bibliothek zur Veröffentlichung für die Öffentlichkeit erstellen möchten, möchten Sie wahrscheinlich nicht, dass Kunden sich mit der Komplexität oder Starrheit des bestimmten DI-Systems befassen, das Sie derzeit bevorzugen. Bibliotheken sind am besten geeignet, wenn es sich um untergeordnete Komponenten handelt, die ohne viele Abhängigkeiten oder umfangreiche Schulungen verwendet werden können. Jedes von Ihnen ausgewählte DI-System ändert sich im Laufe der Zeit und ist möglicherweise nicht mehr mit Clientanwendungen kompatibel.

Frank Hileman
quelle
2

Eine Bibliothek soll eine Black Box mit einer sauberen domänenspezifischen API sein. Es ist kein Problem, Werkzeuge oder Muster zu verwenden, die Sie in einer Bibliothek benötigen, einschließlich DI, solange diese nicht an den Client gelangen und ihn in irgendeiner Weise einschränken.

Wenn Erweiterbarkeits- oder Bibliothekskonfigurationsänderungen erforderlich sind, kann dies dennoch durchgeführt werden, ohne dass ein einziger Kompositionsstamm zwischen der Bibliothek und dem Client freigegeben wird.

Ob Sie Ihre Bibliothek abhängig von einer anderen Bibliothek eines Drittanbieters rechtfertigen können, um DI in Ihrer Bibliothek zu implementieren, ist ein anderes Problem. Beachten Sie jedoch, dass das DI-Muster selbst ohne Abhängigkeiten implementiert werden kann.

astreltsov
quelle
-1

Wenn Sie Bibliotheken (keine Anwendungen) entwickeln, die von anderen verwendet werden sollen, sollten Sie dennoch die Abhängigkeitsinjektion implementieren. Für mich ist der Begriff "Abhängigkeitsinjektion" nur eine Reihe von Praktiken, die zu einer besseren Trennung von Bedenken und einer losen Kopplung führen. Dies macht Ihre Bibliothek gut strukturiert und (meistens) leicht testbar.

In Bezug auf den IoC-Container sehe ich keinen Schaden darin, IoC-Container im Bibliotheksprojekt zu haben. Irgendwo haben Sie einen Kompositionsstamm (einen Einstiegspunkt) in Ihrer Bibliothek, daher ist es für mich absolut sinnvoll, Ihre Abhängigkeiten im Kompositionsstamm zu verkabeln. Wie Sie es tun, liegt ganz bei Ihnen.

Als Beispiel habe ich kürzlich eine Bibliothek zum Erfassen von Signaturen und eine Bibliothek zum Scannen von Barcodes verwendet. Beide waren einfache Interop-Bibliotheken (COM-Wrapper). Für jede Bibliothek musste ich sie initialisieren, bevor ich etwas tun konnte. Zum Beispiel:

var isReady = _signatureCapture.Initialise()
if (isReady)
{
   // Do stuff
}

Die Barcode-Scan-Bibliothek war sehr ähnlich:

_scanner.Initialise();
_scanner.OnScan += OnScanHandler;

Ich habe beide Bibliotheken verwendet und ich habe keine Ahnung, ob sie IoC-Container verwenden oder nicht. Ich weiß jedoch, dass sich die Einstiegspunkte in die Bibliothek in den InitialiseMethoden befinden. Ich vermute, dass alle Abhängigkeiten in der InitialiseMethode verkabelt sind , die als Kompositionswurzel dient.

Wenn Sie sich Sorgen machen, sich auf einen IoC-Container eines Drittanbieters zu verlassen, können Sie mit Ihrer eigenen, stark vereinfachten Implementierung rollen. Entwickler machen sich oft Sorgen, dass die Bibliothek veraltet oder durch etwas Besseres ersetzt wird, aber in Wirklichkeit habe ich noch kein Projekt gesehen, bei dem das Team beschlossen hat, einen IoC-Container gegen den anderen auszutauschen.

CodeART
quelle
4
Bibliotheken sollten unnötige Abhängigkeiten vermeiden. Außer im Fall einer sehr komplexen Bibliothek, die eher einer Anwendung ähnelt, möchten die meisten Bibliotheksbenutzer keine Abhängigkeit von einer bestimmten DI-Implementierung.
Frank Hileman
-2

Das Schöne an externen Bibliotheken ist, dass sie tun sollten, was immer sie sagen, und gleichzeitig eine einfache, unkomplizierte Oberfläche bereitstellen. Wie komplex es tatsächlich ist, sollte es nicht Sache des Entwicklers sein, der es implementiert. Wenn DI die Arbeit des API-Entwicklers tatsächlich weniger komplex macht, ist es zu 100% sinnvoll, sie zu verwenden, solange sie ordnungsgemäß verwendet wird und ihr Modul am Einstiegspunkt der API deklariert wird. Bei der Entwicklung einer MVC-App vor kurzem habe ich die Datenschicht mithilfe eines Repository-Musters abstrahiert und noch weiter abstrahiert, indem ich eine Service-Schicht zwischen der MVC-App und der Repository-Schicht platziert habe, beides Klassenbibliotheksprojekte. Ich hatte eine ICache-Schnittstelle, die einer Cache-Klasse für meinen Dienstkontext zugeordnet war. Ich habe es ursprünglich mit MVC.Web.Cache implementiert, aber bei einer späteren Iteration habe ich es gegen System.runtime ausgetauscht. Cache und Sie können sich nur vorstellen, wie groß der Umfang dieses Refactors ohne meine Verwendung von DI gewesen wäre. Also mein Rat; "Tue es".

abdulgafar jagun
quelle
Dieser Beitrag ist ziemlich schwer zu lesen (Textwand). Hätten Sie etwas dagegen bearbeiten sie in eine bessere Form ing?
Mücke