|
组装包括两个部分,界面的装配、插件交互关系的装配。下面介绍三种组装策略,简单分析一下不同组装策略的差异。
插件系统的生命期
插件是独立的模块,每个模块向用户提供一部分功能,只有将几个模块组合起来才能真正给用户带来价值。
插件系统分为装载期和运行期两个阶段。
装载期时,装载程序将不同的插件按照配置文件组装起来,主要包括界面布局和插件接口之间的调用关系。
装载完成后的插件系统处于运行期。运行期时需要从两个角度分析:插件内部行为,包括内部的函数调用及用户输入的响应和插件之间的交互。
在装载期需要装载器将系统必要的插件按照需求组装成可运行的系统。下面介绍三种组装过程,会采用“积木”的隐喻解释工作原理。
三种组装策略
1.Eclipse的最小化组装
说起插件不能不提到Eclipse了,它是一个非常成功的插件系统,属于微内核。
首先介绍两个概念,“插件”和“插件模板”。插件是在系统运行期时的功能模块,从程序员的角度而言,是一些实例对象。插件模板指的是配置文件,有插件本身的配置信息,比如图标、标题等,另外还有插件之间的关联关系(扩展和扩展点的概念),可以通过指定的插件模板生成插件。
这里认为Eclipse是最小化的组装是因为在Eclipse中装载过程是分散到系统中的各个角落。由父插件装载并创建子插件,装载并创建就是组装过程。
整个Eclipse在装载期只会将配置文件读入内存,生成插件模板体系,随后创建第一个插件。至于其他的插件都是主插件的子插件。装载器的功能很简单,原因在于其将组装过程分散到系统中的各级父插件身上。
用积木的隐喻来解释Eclipse的插件组装过程就是,由装载器将第一个积木搭好,然后把设计图纸放到大家都看得到的白板上。如果有人想看某个积木之上的东西,那么这个积木中自带的一个小的装载机器会将积木之上的其他积木马放上来。
可以看到,Eclipse中的积木是非常智能的。因为它们本身就会搭积木,这样系统的装载器,要做的事情就非常少了。
2.装载时绑定
装载时需要确定插件的界面呈现,插件之间的交互。如果设计的好,插件的外观布局是可以和插件的交互分开处理的。
插件的外观布局由配置文件指定,在装载期,通过读取系统的配置文件可以确定某一插件放在什么地方。在装载期将所有的插件界面全部放置到系统中,这样系统的运行期在界面上和普通的系统没有什么区别。如果需要加载,可以用代理对象来实现,对装载期没有影响。
插件之间的交互同样通过配置文件指定。这时候需要用到接口才可隔离不同的插件实现,接口是积木的外观。装载器可以将所有的插件之间的接口绑定起来,可以使用观察者模式处理。在系统装载的过程中,通过外部的指定,将所有观察者的接口注册到各个目标中,这样目标和观察者之间就可以相互通信。
用这种方式组装系统,在系统的装载期由装载器就已经将整个积木模型搭建好了。每个积木完成自己分内的事,处理好和自己吻合起来的积木之间的关系就可以。
3.运行时绑定
界面绑定和上面说的没有什么区别,但将插件之间的关系,也就是每个插件内部存储的观察者列表去掉了。这样保证插件本身是最清洁的。
插件与其观察者之间的匹配关系抽象成关系模式,这种对应关系在全局的关系列表中存在。
和第二种对比起来看,界面部分装载没有区别,但第二种组装是将插件交互关系在装载时绑定到插件内部,而这种是将插件关系存成一张列表,每个插件在需要调用的地方动态获得观察者的列表,实现采用的是以前介绍过的关系模式。
对比分析
1.延时加载
三种组装策略中都可以实现延时加载的方式。这里将延时加载单独拿出来说是因为这个在插件系统中太重要了。
Eclipse中的延时加载是天生的,装载的策略决定了插件本身就是延时加载的。但后两种却没有这个能力,不过我们能够使用代理插件来实现同样的效果。基本的思路就是,按照配置文件生成插件的代理对象,装载期将所有的代理对象装配起来,在运行期由代理的特性自动装载真实的插件。对于装载器和运行期而言,延时加载是透明的。
2.职责分配
第一种的装载过程没有和运行期明确分开,并且插件也会负责装载,所以说这里的职责分配是不明确的,但带来的一个好处就是微内核。其他两种的装载和运行期分的比较清楚,但内核比较大。
3.插件交互
在Eclipse中插件的组织是一个树形结构,插件之间的交互非常严格。当然,从系统耦合度的方面而言,这样严格的限制是有好处的,但这种树状的组织结构并不能满足所有的要求,尤其在行业软件中。系统中的插件数量多,交互非常复杂,如果是一种图状的结构,第一种模式就不适合。第二种和第三种都能满足图状交互的特点。
4.装载期效率
Eclipse的装载最简单,效率是最高的。第二种装载最复杂,效率也是最低的。第三种介于两者之间。
5.运行期效率
Eclipse运行时需要即时装配插件,运行的效率较低。第二种所有系统运行需要的因素都在装载期处理好,系统运行时都是静态调用,性能最好。第三种介于两者之间。
如果插件之间频繁交互的话,第一种和第二种都是会在插件内部存储一个关联的接口列表,所以性能上完全能够保证。
|