Ich baue eine WinForms-Anwendung mit einer UI, die nur aus NotifyIcon
und ihrer dynamisch bestückten ContextMenuStrip
besteht. Es gibt eine MainForm
, um die Anwendung zusammen zu halten, aber das ist nie sichtbar.IoC: Abhängigkeiten von Event-Handlern verschalten
Ich machte mich daran, dies so solide wie möglich zu bauen (mit Autofac, um die Objektgrafik zu handhaben) und bin ziemlich zufrieden mit meinem Erfolg, meist auch ziemlich gut mit dem O-Teil. Mit der Erweiterung, die ich gerade implementiere, scheint es, dass ich einen Fehler in meinem Design entdeckt habe und etwas umbauen muss; Ich denke, ich weiß, wie ich gehen muss, aber ich weiß nicht genau, wie ich die Abhängigkeiten genau definieren soll.
Wie oben erwähnt, wird das Menü nach dem Start der Anwendung zum Teil dynamisch ausgefüllt. Zu diesem Zweck definierte I eine IToolStripPopulator
Schnittstelle:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
Eine Implementierung dieses in die MainForm
eingespritzt wird, und die Methode aufruft Load()
PopulateToolStrip()
mit den ContextMenuStrip
und einem Handlers in der Form definiert ist. Die Abhängigkeiten des Populators beziehen sich nur auf das Abrufen der Daten, die für die Menüelemente verwendet werden sollen.
Diese Abstraktion hat gut durch ein paar evolutionäre Schritte gearbeitet, aber ist nicht mehr ausreichend, wenn ich mehr als einen Event-Handler, z. weil ich mehrere verschiedene Gruppen von Menüpunkten erstelle - immer noch versteckt hinter einer einzigen IToolStripPopulator
Schnittstelle, weil das Formular damit überhaupt nichts zu tun haben sollte.
Wie gesagt, ich glaube, ich weiß, was die allgemeine Struktur sein sollte - ich die IToolStripPopulator
Schnittstelle zu etwas spezielleren * umbenannt und eine neue, dessen PopulateToolStrip()
Methode nicht nehmen einen EventHandler
Parameter, die stattdessen in injiziert wird das Objekt (was auch viel mehr Flexibilität bezüglich der Anzahl von Handlern ermöglicht, die von einer Implementierung usw. benötigt werden). Auf diese Weise kann mein "vorderster" IToolStripPopulator
sehr einfach ein Adapter für eine beliebige Anzahl von spezifischen sein.
Nun, was ich unklar bin, ist die Art, wie ich die EventHandler-Abhängigkeiten auflösen sollte. Ich denke, die Handler sollten alle im MainForm
definiert werden, weil das alle anderen Abhängigkeiten hat, die benötigt werden, um auf die Menüereignisse richtig zu reagieren, und es "besitzt" auch das Menü. Das würde bedeuten, dass meine Abhängigkeiten für IToolStripPopulator
Objekte, die schließlich in das MainForm-Objekt injiziert werden, Abhängigkeiten vom MainForm
-Objekt selbst unter Verwendung von Lazy<T>
benötigen.
Mein erster Gedanke war die Definition einer IClickHandlerSource
Schnittstelle:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
Dieses von meiner MainForm
umgesetzt wurde, und meine spezifischen IToolStripPopulator
Implementierung nahm eine Abhängigkeit von Lazy<IClickHandlerSource>
. Während das funktioniert, ist es unflexibel. Ich würde entweder separate Schnittstellen für eine potentiell wachsende Anzahl von Handlern definieren müssen (die OCP mit der MainForm
Klasse schwer verletzen) oder IClickHandlerSource
kontinuierlich erweitern (hauptsächlich verletzend ISP). Direkt Abhängigkeiten von den Event-Handlern zu nehmen, scheint auf der Konsumentenseite eine nette Idee zu sein, aber die Konstrukteure über Eigenschaften von Lazy-Instance (oder ähnlichem) individuell zu verdrahten, scheint ziemlich chaotisch - wenn überhaupt möglich.
Meine beste Wette scheint derzeit dabei, um:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
Die Schnittstelle nach wie vor von MainForm
und injizierte als faul Singleton implementiert werden würde, und EventHandlerType
eine benutzerdefinierte Enum mit den verschiedenen Arten sein würden, was ich brauche. Dies wäre immer noch nicht sehr OCP-konform, aber einigermaßen flexibel. EventHandlerType
würde natürlich für jeden neuen Typ von Event-Handler eine Änderung haben, ebenso wie die Auflösungslogik in MainForm
, zusätzlich zu dem neuen Event-Handler selbst und der (wahrscheinlich) neu geschriebenen zusätzlichen Implementierung von IToolStripPopulator
.
Oder .... eine eigene Implementierung von IEventHandlerSource
, die (als einziges Objekt) auf Lazy<MainForm>
eine Abhängigkeit nimmt und löst die EventHandlerType
Optionen auf die spezifischen Handler in MainForm
definiert?
Ich versuche, eine Möglichkeit zu erwägen, die Event-Handler aus MainForm
in einer realisierbaren Weise zu bekommen, aber kann jetzt nicht ganz scheinen.
Was ist meine beste Option hier, bietet die lockerste Kopplung und eleganteste Auflösung der verschiedenen Event-Handler?
[* Ja, ich wahrscheinlich den Namen haben sollte allein gelassen mit OCP, um wirklich zu erfüllen, aber es sah so besser.]
ich Ihre Frage mehrmals gelesen, aber ich einige Informationen fehlen. Kannst du mehr Code zeigen? Wie sehen beispielsweise die Verbraucher von "IEventHandlerSource" aus und wie sieht die Implementierung von "IEventHandlerSource" aus, und wie wird dies alles registriert? – Steven