我正在构建一个 WinForms 应用程序,其 UI 仅包含 NotifyIcon
及其动态填充的 ContextMenuStrip
。有一个 MainForm
将应用程序保存在一起,但它永远不可见。
我开始尽可能可靠地构建它(使用 Autofac 处理对象图)并且对我的成功非常满意,即使与 O 部分也相处得很好。通过我目前正在实现的扩展,我似乎发现了我的设计中的一个缺陷,需要稍微改造一下;我想知道我需要走的路,但对于如何准确定义依赖关系有点不清楚。
如上所述,菜单在启动应用程序后部分动态填充。为此,我定义了一个 IToolStripPopulator
接口(interface):
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
这个的实现被注入(inject)到
MainForm
中,Load()
方法调用 PopulateToolStrip()
和 ContextMenuStrip
和一个在表单中定义的处理程序。填充器的依赖关系仅与获取用于菜单项的数据有关。这种抽象通过几个进化步骤已经很好地工作了,但是当我需要多个事件处理程序时就不再足够了,例如因为我正在创建几组不同的菜单项 - 仍然隐藏在单个
IToolStripPopulator
界面后面,因为表单根本不应该关心它。正如我所说,我想我知道一般结构应该是什么样的 - 我将
IToolStripPopulator
接口(interface)重命名为更具体的东西*并创建了一个新接口(interface),其 PopulateToolStrip()
方法不采用 EventHandler
参数,而是注入(inject)到对象中(也允许在实现等所需的处理程序数量方面具有更大的灵活性)。这样我的“最重要的” IToolStripPopulator
可以很容易地成为任意数量的特定适配器的适配器。现在我不清楚的是我应该解决 EventHandler 依赖项的方式。我认为处理程序都应该在
MainForm
中定义,因为它具有正确响应菜单事件所需的所有其他依赖项,并且它还“拥有”菜单。这意味着我对最终注入(inject) MainForm 的 IToolStripPopulator
对象的依赖需要使用 MainForm
依赖于 Lazy<T>
对象本身。我的第一个想法是定义一个
IClickHandlerSource
接口(interface):public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
这是由我的
MainForm
实现的,我特定的 IToolStripPopulator
实现依赖于 Lazy<IClickHandlerSource>
。虽然这有效,但它是不灵活的。我要么必须为数量可能不断增加的处理程序定义单独的接口(interface)(使用 MainForm
类严重违反 OCP)或不断扩展 IClickHandlerSource
(主要违反 ISP)。直接依赖事件处理程序在消费者方面看起来是个不错的主意,但是通过惰性实例(或类似的)的属性单独连接构造函数似乎非常困惑 - 如果可能的话。
我目前最好的选择似乎是这样的:
public interface IEventHandlerSource
{
EventHandler Get(EventHandlerType type);
}
该接口(interface)仍将由
MainForm
实现并作为惰性单例注入(inject),而 EventHandlerType
将是具有我需要的不同类型的自定义枚举。这仍然不是非常符合 OCP,但相当灵活。 EventHandlerType
显然会对每种新类型的事件处理程序进行更改,MainForm
中的解析逻辑也是如此,除了新的事件处理程序本身和(可能)新编写的 IToolStripPopulator
的附加实现之外。或者....
IEventHandlerSource
的单独实现(作为唯一对象)依赖于 Lazy<MainForm>
并将 EventHandlerType
选项解析为 MainForm
中定义的特定处理程序?我正在想办法以可行的方式从
MainForm
中实际获取事件处理程序,但现在似乎不太可能。我在这里最好的选择是什么,提供不同事件处理程序的最松散耦合和最优雅的解决方案?
[*是的,为了真正遵守 OCP,我可能应该不理会这个名字,但那样看起来更好。]
最佳答案
What is my best option here, providing the loosest coupling and most elegant resolution of the different event handlers?
不存在通用解决方案,它取决于全局应用程序架构。
如果你想要一个 最松 联轴器,
EventAggregator
在这种情况下,模式可以为您提供帮助(您的 IEventHandlerSource
与此类似):但是,应该非常谨慎地使用全局事件 - 它们可以 涂抹架构,因为在任何地方都可以订阅事件。
DI 和 IoC 中的重要事情:较低的依赖性不应该知道较高的依赖性。
我认为,正如 Leon 之前所说,创建一些像
ITool<T>
这样的界面会更好。并将工具列表存储在 MainForm
中.一些 Action 后MainForm
将调用此工具中的某些方法。
关于c# - IOC : Wiring up dependencies on event handlers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11059298/