一旦解决了加载插件的问题(在 .NET 中,在例外情况下通过 MEF),下一步要解决的是与它们的通信。简单的方法是实现一个接口并使用插件实现,但有时插件只需要扩展应用程序的工作方式,并且可能有很多扩展点。
我的问题是关于如何处理这些扩展点。我已经看到了不同的方法,但我不确定每种方法的优缺点,以及是否有更多更好的方法来实现这一目标:
- 事件:将静态事件添加到我们想要“可扩展”的所有内容中。例如,如果我想为 User 类添加自定义验证,我可以添加 OnValidation 静态事件处理程序,并在构建插件时向其添加事件。
- 消息传递:拥有总线和消息。该插件可以订阅特定消息,并在其他类发布该消息时执行某些操作。该消息应包含插件可以工作的上下文。在验证情况下,逻辑层将发布 UserValidation 消息,插件将在收到消息时采取行动。
- 接口:主机应用程序负责调用所有实现某些接口的插件,并为它们提供当前操作的上下文。在验证的情况下,插件可以使用 Validate(object context) 方法实现 IValidator 或 IUserValidator。
您是否曾经使用过其中一种公开的方法?哪一种最适合您?
在您提问之前,我们的应用程序是一个可扩展的核心(用户、角色和内容管理),可在此基础上构建我们的客户特定的以内容为中心的 Web 应用程序。一切都构建在 ASP.NET MVC 上。
设计决策的关键是分析并清楚地了解插件之间的差异。
例如。在处理静态事件时,您可能必须将每个事件定义为某种形式的令牌、枚举、对象等。必须为每个插件定义一组新的事件自然不利于您的整个设计,特别是在松散耦合和重复使用。
如果您的插件非常不同,您可能会受益于总线/消息传递架构,因为在这种情况下您可以引入插件可以订阅的通信交换的域/类别。 IE。一系列事件和消息可以处于某个兴趣域中。请注意,特定类别内的通信仍然可以利用静态事件,因此这两种选择并不相互排斥。
根据我的经验,插件实现的直接接口是插件架构中最严格的方法。扩展插件接口通常意味着插件和提供者的代码修改。您需要有一个可靠的通用界面,您知道您的应用程序可以运行相当长的一段时间。
通过将设计分解为两个方面,您可能会更容易处理设计 -沟通渠道 and protocol。静态事件处理是一个协议问题,而总线消息传递和直接接口是一个通道问题。
一般来说,我会说协议是最难从一开始就正确设计的,因为您可能对如何划定界限没有明确的感觉。
EDIT:Lars 在他的评论中提出了一个重要的观点 - 如果您的平台支持异常,那么您可以在使用直接接口时集中处理大量错误,从而使插件不必处理通用的错误,并且可能超出其特定域的错误(例如“插件”)加载错误”或“文件打开失败”)。然而,如果每次添加插件时都必须维护接口,那么这些好处似乎就会消失。最糟糕的情况是接口开始变得不一致,因为您从一开始就没有意识到它们应该支持什么。当已经构思出大量插件时,重构整个界面设计并不是一件容易的事。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)