分类:
2007-10-15 16:24:35
一切都是为了更加简单。
从函数到函数库,然后到类,然后到插件,都是因为我们的软件系统日益复杂,人脑毕竟有限,不能同时处理那么多的信息量,所以采用分而治之的方法来管理。
今年已经研究了一年的插件系统,从最开始的懵懵懂懂到现在能有些经验和大家分享,这个过程本身就是很有意思的。
最开始系统中有了十几个插件,经过几个月的慢慢发展,到了大几十个,甚至上百个,这个数量就有些令人头晕了。不过更加麻烦的还不是这近百个插件组装而成的系统,而是某一个插件系统需要调用另外的一个或多个插件系统。这样的话,插件的数量就在100的基数上开始翻倍。
如何做插件系统中的整合成了一个紧急的课题。
前面写过一篇文章,说到了插件系统中的微内核与巨内核之分。不过不管是哪一种,任何一个系统都需要有一个启动点,只不过对于插件系统中的启动步骤来说,它是一个通用,并且和具体业务无关的独立模块。
可以按照下面的图示来简单理解插件系统:
图中的Launcher是插件系统的启动模块,EntryPoint是系统的入口点,作为一个接口给Launcher调用。启动模块通过EntryPoint将系统运行起来。系统中的插件相互协作满足用户的需要。
上面的图将一个插件系统的基本原素描绘出来了。在具体的项目中,这样的一个插件系统中插件的数量可能多达上百个。当两个项目组都在开发各自的产品,项目组A需要将项目组B开发的系统集成到自己的系统中时,就要开始考虑集成的问题了。
系统中的插件之间存在父子关系,任何一个插件都可以作为另外一个插件的子插件存在。
如果将系统B作为系统A中某一个插件的子插件是不是就可以解决集成问题了呢?——不错,一个简单但实用的解决方法。
可以将插件系统考虑成一个函数库,函数库中的几百个函数相互协作完成一系列复杂的功能。现在我们需要在自己写的函数中包含上面函数库中的所有功能怎么办,简单的做法是将函数库中的某个入口函数作为子函数调用就可以了。
下面介绍的集成方案基本上就是这个思路。
EntryPoint是插件系统的启动模块调用系统功能的接口,这个接口是非常简单的,很多时候仅有一个Run方法,直接对应到用户的双击打开程序的操作。
在系统A中要调用系统B时,显然一个简单的Run方法不能满足要求,这里另外提出一个系统的入口点(端点)Endpoint。
两者的区别在于,EntryPoint对应到Launcher的启动过程,参数简单;Endpiont对应到其他系统的交互过程,参数复杂,需要通过Endpoint传递其他系统需要的信息。
有了每个系统的端点,还需要将这些端点组合起来,保证插件系统之间的相互通信。类似于电脑中的总线概念。一旦每个系统的Endpoint挂接到了总线上,插件系统就可以通过总线查找到自己需要交互的其他插件系统了。
这里的总线用关系管理器来实现。因为Endpoint在插件系统中也是作为一个插件存在,这个插件的职责就是和外界交互。关系管理器可以处理任何插件之间的交互,尽管插件并不在同一个系统中。
在系统A中呈现系统B的功能有多种表现形式,比如说在系统A的某个地方放上一个Button,点击后系统B出现;或者在系统A中放上一个页签,和一般功能并列将系统B呈现在系统A中。不管怎样呈现,可以将系统B看作系统A的一个插件。这个插件就是图中的Linker。
Linker是系统B的一个代理插件,它本身并没有实现业务,只是将与系统B的交互以插件的形式呈现在系统A中。Linker通过总线找到对应的插件系统并将它启动,同时负责与它的交互。
Endpoint用的是Adapter的思想,将自身系统的功能以规定好的交互方式发布到总线上,这样其他插件系统才能与之进行交互。这种方法在系统的集成中用得非常多,已经从设计模式上升到了架构模式的层次。
有了这种适配器的方式,不仅仅是插件系统可以集成,甚至非插件系统同样也可以集成到插件系统中来。所作的就是需要给非插件系统提供一个Adapter插件。对于其他插件系统来说,这个非插件系统在BUS的表现也和插件系统没有差别了。
上面提出了一种插件系统的集成方案,目前正在逐步的尝试,过程中还遇到了一些细节上的问题,今后等我慢慢整理出来再和大家分享。
现在只是做了插件系统与插件系统之间的集成,虽然从理论上说,插件系统与非插件系统的集成也同样可行,不过目前还没有实践,不敢妄下定论。等有了机会再好好研究一下这方面的内容。如果哪位朋友有一些好的经验愿意分享,在下洗耳恭听:)