6

一旦加载插件的问题得到解决(在 .NET 中通过 MEF 的情况下),下一步要解决的是与它们的通信。简单的方法是实现一个接口,使用插件实现,但有时插件只需要扩展应用程序的工作方式,可能会有很多扩展点。

我的问题是关于如何处理这些扩展点。我已经看到了不同的方法,但我不确定每种方法的优缺点,以及是否有更多更好的方法来实现这一点:

  • 事件:将静态事件添加到我们想要“可扩展”的所有内容中。例如,如果我想为 User 类添加自定义验证,我可以添加一个 OnValidation 静态事件处理程序,并在构造它时从插件向它添加事件。
  • 消息:有总线和消息。该插件可以订阅特定消息并在其他一些类发布该消息时执行某些操作。该消息应包含插件可以工作的上下文。在验证的情况下,逻辑层会发布一条 UserValidation 消息,插件会在收到消息时采取行动。
  • 接口:宿主应用程序负责调用所有实现特定接口的插件,并为它们提供当前操作的上下文。在验证的情况下,插件可以使用 Validate(object context) 方法实现 IValidator 或 IUserValidator。

您曾经使用过其中一种公开的方法吗?哪一个最适合您?

在您问之前,我们的应用程序是一个可扩展的核心(用户、角色和内容管理),可在此基础上构建我们客户特定的以内容为中心的 Web 应用程序。一切都建立在 ASP.NET MVC 之上。

4

2 回答 2

2

您的设计决策的关键是分析并清楚地了解插件彼此之间的差异。

例如,在处理静态事件时,您可能必须将每个事件定义为某种形式的令牌、枚举、对象等。必须为每个插件定义一组新的事件自然不利于您的整个设计,尤其是在松散耦合方面和重用。

如果您的插件非常不同,您可能会受益于总线/消息传递架构,因为在这种情况下您可以引入插件可以订阅的通信交换的域/类别。即,一系列事件和消息可以在某个兴趣域中。请注意,某个类别内的通信仍然可以利用静态事件,因此这两种选择并不相互排斥。

根据我的经验,插件实现的直接接口是插件架构中最严格的方法。扩展插件接口通常意味着插件和提供者的代码修改。您需要有一个可靠的通用界面,您知道您的应用程序可以运行相当长的一段时间。

通过将设计分解为通信通道协议两个方面,您可能更容易处理设计。静态事件处理是一个协议问题,而总线消息传递和直接接口是一个通道问题。

一般来说,我会说协议是最难从一开始就正确设计的,因为您可能对划定界限的一般性或具体性没有扎实的感觉。

编辑: Lars 在他的评论中提出了一个重要的观点 - 如果您的平台支持异常,您可以在使用直接接口时集中处理许多错误,从而使插件不必处理通用的错误并且可能超出其特定域(例如“插件加载错误”或“文件打开失败”)。但是,如果每次添加插件时都必须维护接口,这些好处似乎会消失。最坏的情况是接口开始变得不一致,因为您从一开始就没有意识到它们应该支持什么。在已经构思出大量插件的情况下重构整个界面设计并不是一件容易的事。

于 2009-11-18T12:39:30.330 回答
0

我会选择观察者模式。来自GOF:

定义对象之间的一对多依赖关系,以便当一个对象更改状态时,它的所有依赖项都会自动得到通知和更新。

也称为发布订阅,我建议它与您的示例中的情况二最接近。

于 2009-11-18T12:44:31.697 回答