Ich hatte in einem früheren Spielprojekt etwas von einem praktischen Service-Locator-Anti-Pattern. Ich möchte das durch die Abhängigkeitsinjektion ersetzen. autofac sieht für mich wie der wahrscheinlichste DI-Container aus, da er relevante Funktionen zu haben scheint - aber ich kann es nicht herausfinden wie man das erreicht, wonach ich suche.
Anstelle eines einzelnen Service-Locators hatte ich einen Service-Locator, der an seinen übergeordneten Service delegieren konnte (in der Tat "scoped" Services):
%Vor%Zur Vereinfachung wurde das Spiel aus einem Baum mit komponentenbasierten Klassen aufgebaut:
%Vor%So konnte ich (und tat) Baumstrukturen bauen wie:
%Vor%Und jede Komponente könnte einfach den ServiceLocator aufrufen, mit dem sie konstruiert wurde, um alle benötigten Dienste zu finden.
Vorteile:
Komponenten müssen sich nicht darum kümmern, wer die Dienste, die sie nutzen, oder wo diese Dienste leben, implementiert. solange die Lebenszeiten dieser Dienste gleich oder größer als ihre eigenen sind.
Mehrere Komponenten können denselben Dienst verwenden, dieser Dienst kann jedoch nur so lange bestehen, wie er benötigt wird. Insbesondere können wir einen ganzen Teil der Hierarchie dispose (), wenn der Spieler eine Ebene verlässt, was viel einfacher ist, als Komponenten komplexe Datenstrukturen neu zu erstellen, um sie an die Idee anzupassen, dass sie sich jetzt auf einer völlig neuen Ebene befinden. p>
Nachteile:
Wie Mark Seeman darauf hinweist, ist Service Locator ein Anti-Pattern .
Einige Komponenten würden Dienstanbieter instanziieren, weil ich (der Programmierer) weiß, dass verschachtelte Komponenten diesen Dienst benötigen oder ich (der Programmierer) weiß, dass das Spiel funktionieren muss z.B AI läuft in der Spielwelt , nicht weil der Instanziierer diesen Dienst per se benötigt.
Im Geiste von DI möchte ich das gesamte Wissen über "Service Locators" und "Scopes" von Components entfernen. Sie würden (über DI) Konstruktorparameter für jeden von ihnen konsumierten Dienst erhalten. Um dieses Wissen aus den Komponenten herauszuhalten, muss der Kompositionswurzel für jede Komponente Folgendes angeben:
Ich möchte das intuitive schreiben:
%Vor%Und in der Lage sein, in der Komposition root das
anzugeben Ich muss gestehen, dass ich völlig verloren bin, wenn es um die letzten beiden geht. Ich werde hier meine zahlreichen fehlgeschlagenen Autofac-basierten Versuche nicht aufzählen, da ich über einen langen Zeitraum hinweg einige Dutzend gemacht habe und keiner von ihnen im Entferntesten funktional war. Ich habe die Dokumentation ausführlich gelesen - ich weiß, dass lebenslange Bereiche und Owned<>
in dem Bereich sind, den ich betrachte, aber ich kann nicht sehen, wie man Abhängigkeiten in Abhängigkeiten transparent einfügt, wie ich es sehe - aber ich fühle, dass DI im Allgemeinen scheint genau das zu erleichtern, was ich tun will!
Wenn das gesund ist, wie kann ich das erreichen? Oder ist das nur teuflisch? Wenn ja, wie würden Sie eine solche Anwendung strukturieren, die DI sinnvoll einsetzt, um zu vermeiden, dass Objekte rekursiv umgangen werden, wenn die Lebensdauer dieser Objekte abhängig vom Kontext variiert, in dem das Objekt verwendet wird?
LifetimeScopes klingen wie die Antwort. Ich denke, was du im Grunde tust, ist das Verbinden von Lebensbereichen mit Bildschirmen. So würden ShootingComponent und Freunde mit .InstancePerMatchingLifetimeScope("Screen")
registriert werden. Der Trick besteht dann darin, dass jeder Bildschirm in einem neuen LifetimeScope erstellt wird, das als "Bildschirm" gekennzeichnet ist. Mein erster Gedanke wäre, eine Bildschirmfabrik so zu machen:
Das ist völlig ungeprüft, aber ich denke, das Konzept macht Sinn.
Zufällig arbeite ich derzeit mit ähnlichen Anforderungen (Autofac verwenden) und hier ist das, was ich bisher herausgefunden habe:
Hier ist ein Beispiel, wie ich es gemacht habe:
%Vor%In dem von Ihnen angegebenen Beispiel würde ich die Auflösung von AIComponent zwischen Anfangs- und Endaufrufen der obigen Klasse setzen, wenn Sie Ebenen durchlaufen.
Wie gesagt, ich bin mir sicher, dass Sie in Ihrer Entwicklungsstruktur eine bessere Möglichkeit finden werden, dies zu tun. Ich hoffe, dies gibt Ihnen die Grundidee, wie Sie es umsetzen können, vorausgesetzt, meine Erfahrung ist als eine "gute" Art, dies zu tun.
Viel Glück.
Tags und Links c# dependency-injection autofac circular-dependency