插件框架中的消息传递
首先,我的博客上提供了此问题的一些背景信息:
- http://www.codebork.com/coding/2008/06/25/message-passing-a-plug-framework.html
- http://www.codebork.com/coding/2008/07/31/message-passing -2.html
我知道描述不是很清楚,所以我将尽力总结我在这里尝试的内容。 该应用程序是个人理财计划。 有关框架本身的更多背景信息可以在本文末尾找到。
该框架可以处理许多不同类型的插件(例如,帐户、导出、报告等)。 然而,我专注于一类特定的插件,即所谓的数据插件,因为正是此类给我带来了问题。 我有一类用于帐户的数据插件,一类用于交易等。
我正在进行大规模的重构,这给我留下了以下数据插件的架构:
- 数据插件对象(实现初始化、安装和插件元数据)[实现
IDataPlugin
] - 数据对象(例如帐户)[实现,例如
IAccount
] - 要创建的工厂数据对象的实例[实现,例如,
IAccountFactory
]
以前,数据对象和插件对象被合并为一个,但这意味着必须为每个对象实例化一个新的事务插件帐户中记录的交易导致了许多问题。 不幸的是,这种重构破坏了我的消息传递。 数据对象实现了 INotifyPropertyChanged,因此我遇到了一个新问题,而且我不确定如何解决这个问题:插件对象正在向消息代理注册事件,但是实际触发事件的是数据对象。 这意味着订阅插件当前必须订阅每个创建的帐户、交易等!这显然是不可扩展的。
据我目前所知,我有两种可能的解决方案:
- 让数据插件对象成为数据对象和消息代理的中间人,可能批量更改通知。 我不喜欢这个,因为它给消息传递系统增加了另一层复杂性,我觉得我应该可以不这样做。
- 废弃当前基于事件的实现并使用其他更易于管理的东西(内存中的 WCF?!)。
所以我想我真的在问:
- 你将如何解决这个问题?
- 您认为我忽略了哪些潜在的解决方案?
- 我的方法是否模糊地步入正轨/明智?! :-)
正如您从博客文章的日期中可以看出的那样,这个问题的某些变体已经困扰我很长一段时间了! 因此,我们将不胜感激任何和所有的回应。
该框架本身的背景如下:
我的插件框架由三个主要组件组成:插件代理、首选项管理器和消息代理。 插件代理负责插件的基本工作:发现和创建插件。 首选项管理器管理框架和各个插件的用户首选项,例如启用哪些插件、应在何处保存数据等。通信通过发布/订阅进行,消息代理位于中间,收集所有内容发布的消息类型和管理订阅。 发布/订阅目前是通过 .NET
INotifyPropertyChanged
接口实现的,该接口提供了一个名为PropertyChanged
的事件; 消息代理构建所有实现 INotifyPropertyChanged 的插件的列表,并订阅此事件的其他插件。 消息传递的目的是让账户和交易插件通知存储插件数据发生了变化,以便可以保存数据。
First off, there's a bit of background to this issue available on my blog:
- http://www.codebork.com/coding/2008/06/25/message-passing-a-plug-framework.html
- http://www.codebork.com/coding/2008/07/31/message-passing-2.html
I'm aware that the descriptions aren't hugely clear, so I'll try to summarise what I'm attempting as best I can here. The application is a personal finance program. Further background on the framework itself is available at the end of this post.
There are a number of different types of plug-in that the framework can handle (e.g., accounts, export, reporting, etc.). However, I'm focussing on one particular class of plug-in, so-called data plug-ins, as it is this class that is causing me problems. I have one class of data plug-in for accounts, one for transactions, etc.
I'm midway through a vast re-factoring that has left me with the following architecture for data plug-ins:
- The data plug-in object (implementing intialisation, installation and plug-in metadata) [implements
IDataPlugin<FactoryType>
] - The data object (such as an account) [implements, e.g.,
IAccount
] - A factory to create instances of the data object [implements, e.g.,
IAccountFactory
]
Previously the data object and the plug-in object were combined into one, but this meant that a new transaction plug-in had to be instantiated for each transaction recorded in the account which caused a number of problems. Unfortunately, that re-factoring has broken my message passing. The data object implements INotifyPropertyChanged
, and so I've hit a new problem, and one that I'm not sure how to work around: the plug-in object is registering events with the message broker, but it's the data objects that actually fire the events. This means that the subscribing plug-in currently has to subscribe to each created account, transaction, etc.! This is clearly not scalable.
As far as I can tell at the moment I have two possible solutions:
- Make the data plug-in object a go-between for the data-objects and message broker, possibly batching change notifications. I don't like this because it adds another layer of complexity to the messaging system that I feel I should be able to do without.
- Junk the current event-based implementation and use something else that's more easily manageable (in-memory WCF?!).
So I guess I'm really asking:
- How would you solve this problem?
- What potential solutions do you think I've overlooked?
- Is my approach even vaguely on-track/sensible?! :-)
As you will be able to tell from the dates of the blog posts, some variant of this problem has been taxing me for quite a long time now! As such, any and all responses will be greatly appreciated.
The background to the framework itself is as follows:
My plug-in framework consists of three main components: a plug-in broker, a preferences manager and a message broker. The plug-in broker does the bread-and-butter plug-in stuff: discovering and creating plug-ins. The preferences manager manages user preferences for the framework and individual plug-ins, such as which plug-ins are enabled, where data should be saved, etc. Communication is via publish/subscribe, with the message broker sitting in the middle, gathering all published message types and managing subscriptions. The publish/subscribe is currently implemented via the .NET
INotifyPropertyChanged
interface, which provides one event calledPropertyChanged
; the message broker builds a list of all plug-ins implementingINotifyPropertyChanged
and subscribes other plug-ins this event. The purpose of the message passing is to allow the account and transaction plug-ins to notify the storage plug-ins that data has changed so that it may be saved.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
现在还为时尚早,但您是否考虑过尝试使用 MEF 而不是自己动手?
It's early yet, but have you considered trying to use MEF instead of rolling your own?
哇! 大问题! :)
如我错了请纠正我。 现在,您的基本解决方案是一种观察者模式,其中数据对象(帐户等)通知其状态的变化。 您认为问题在于订阅插件必须在每个对象中注册才能处理通知。
这本身不是问题,您可以将事件控件放在 域模型 中,但我建议您创建一个服务层并在该层中执行此事件通知。 这样,只有一个对象负责发布通知。
Martin Fowler 在他的博客中有一系列事件模式。 看看! 很好读。
Wow! Big question! :)
Correct me if I'm wrong. Your basic solution now is kind of an Observer pattern, where the data object (Account, etc) notifies about changes in their states. You think that the problem is that the subscribing plugin has to register in every object to be able to handle notifications.
That's not a problem per se, you can put the event control in the Domain Model, but I suggest you create a Service Layer and do this event notifications in this layer. That way just one object would be responsible for publishing notifications.
Martin Fowler have a series of Event Patterns in his blog. Check it out! Very good reading.
这是我对你的问题的理解:你有一个插件对象,它可能必须监听 x 数据对象上的事件 - 但你不想订阅每个数据对象上的事件。 我假设几个插件可能想要监听同一数据对象上的事件。
您可以创建一个会话类型对象。 每个插件都会侦听会话对象上的事件。 数据对象不再引发事件 - 它调用会话对象来引发事件(参数之一必须是引发事件的数据对象)。
这意味着您的插件只需订阅一个事件,但它们会从所有数据对象中获取该事件。
另一方面,如果一次只有一个插件监听数据对象,为什么不让数据对象直接调用插件呢?
This is my understanding of your question: You have a plugin object that may have to listen for events on x data objects - you don't want to subscribe to the event on each data object though. I'm assuming that several plugins may want to listen to events on the same data object.
You could create a session type object. Each plugin listens for events on the session object. The data object no longer raises the event - it calls the session object to raise the event (one of the parameters would have to be the data object raising the event).
That means that your plugins only have to subscribe to one event, but they get the event from all data objects.
On the other hand, if only one plugin will ever listen to a data object at a time, why not just have the data object call the plugin directly?