[1] 插件架构(PLUG-IN)
网上的一种比较好对插件的定义是:插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)也称为扩展,是一种遵循一定规范的应用程序接口编写出来的程序,主要是用来扩展软件功能。很多软件都有插件,有些由软件公司自己开发,有些则是第三方或软件用户个人开发。提起插件架构,可能大家对插件不太熟悉。其实在我们经常使用的大型软件中,有很多是使用插件架构的,比如VS 2005、AutoCad、PhotoShop、ArcGIS,也有很多著名的插件,如例如Photoshop中滤镜插件,Wordpress博客程序有成千上万的插件等。
我试着在我的软件安装目录下搜索:plug in,结果是搜到一大堆结果,如下图:
什么是插件架构?我认为一个采用插件架构的系统,用一个形象比喻就像大型服务器的磁盘阵列。大家知道大型主机是24小时运行的,更换硬盘是不可能通过关闭主机来进行的,流行采用的是热插拔的方式进行的。插件系统也是类似的,一个插件模块的更新不需要对整个系统进行重新编译,不会影响其它插件模块。要达到这样的效果,我认为插件系统的本质特点是系统配置化。所谓系统配置化,就是无论系统的界面还是模块都是通过配置进行的,用户可以通过修改这个配置来达到他们所要的效果。界面配置化很容易理解,就是界面能够用户的喜好和需要来进行配置。模块配置可能大家接触比较少,之后的文章我会具体谈谈这个问题。这里的模块其实也可以成为插件。在插件系统里主程序调用这些插件是动态加载插件DLL来实现对插件的调用的。因此一般用户可以很自由地管理插件,比如决定加载哪个插件和不加载哪个插件。
一.插件架构的优点
1.方便的定制性
软件的定制化服务来源于两个需要:首先是在个性化时代用户需要一个个性化的软件,例如是软件界面的个性化;其次单纯的商业软件很难完全满足用户业务流程的需要,这样可以通过对商业软件实施定制化来满足用户业务流程的需要。插件结构的灵活性保证了软件方便的定制性。
2.方便开发和测试
一个设计良好的系统的一个特征是:模块之间的低耦合性和模块内部的高内聚性。一般而言,软件架构的灵活性、可扩展性和开发、测试的方便性呈一种正相关的关系。插件系统的一个突出特征采取主程序动态加载插件DLL的方式,这在一定程度上减轻主程序和插件模块的耦合性。同时。在开发的时候只需划分好模块,各个插件开发人员只需遵循接口协议,就能开发出互不影响的插件模块(以前有次项目经历是由于项目开发人员的经验不足或沟通不够造成在各个模块功能开发完成之后整个系统编译时出现循环依赖或函数重命名之类的现象,插件系统基本上可以杜绝这类现象)。在进行程序调试的时候同样很容易显示插件架构的优势,比如在检测内存泄露时可以设置手动设置加载或不加载哪个模块来判断内存泄露出现在哪个模块,同时在出问题时也可以很快能判断出哪个模块出现了问题。
3.方便更新,从而延长软件的生命力
由于插件采用动态加载的方式,而且遵循的是统一的接口协议。在进行软件升级时,只需要将插件DLL进行替换即可。具体的方式可以设定升级网站,用户可以从升级网站下载新的升级文件替换本地的文件,这个可以参考Windows Update的实现。
4.增加软件销售的灵活性。
由于插件架构的灵活性,意味着主程序和插件之间可以进行很自由的组合。比如主程序实现基本的功能,扩展功能都由插件实现。很多时候用户并不需要一个大而全的软件,而是一个满足业务的实用的软件。通过模块的自由组合,可以给用户提供多个版本,满足用户的多样化需要,同时也可以灵活应对用户业务的变化。
二.插件架构的缺点
1. 前期的设计难度比一般的应用系统大
设计一个插件系统比设计一个一般的应用系统,其难度的增加在于扩展性方面的设计考虑,这个需要进行多方面的考虑,比如如何最大限度满足插件开发人员的开发需要,又比如之后我要谈到的一个关键问题就是主程序是如何和插件进行交互的;又比如要考虑如何适应用户业务的变化。
2.需要插件开发人员熟悉协议
主程序和插件模块之间的通讯依靠双方约定的接口协议进行。插件开发人员要开发插件的话,需要熟悉接口协议。这就需要系统的设计人员提供必要的教程等培训资料,有必要的话还要进行培训。
插件架构的大体分类:
i> 脚本式
使用某种语言把插件的程序逻辑写成脚本代码。而这种语言可以是 Python ,或是其他现存的已经经过用户长时间考验的脚本语言。甚至,你可以自行设计一种脚本语言来配合你程序的特殊需要。当然,用当今最流行的 XML 是再合适不过了。
这种形式的特点在于,稍有点编程知识的用户就可以自行修改你的脚本( ^_^ 假如你不加密它的话)。我们无法论证这是好处还是坏处。因为,这种情况所造成的后果是不可预知的。
ii> 动态函数库 DLL
插件功能以动态库函数的形式存在。主程序通过某种渠道(插件编写者或某些工具)获得插件 DLL 中的函数签名,然后在合适的地方调用它们。用过 Matlab 的读者都知道, Matlab 中的各项功能几乎都是些动态链入的函数。
iii> 聚合式
顾名思义,就是把插件功能直接写成 EXE 。主程序除了完成自己的职责外,还负责调度这些“插件”。我不喜欢这种形式。这使插件与插件之间,主程序与插件之间(主要是这一点)的信息交流困难了许多。巴比伦塔的失败 [1] 从某种程度上讲就是信息交流无法实现造成的。
iv> COM 组件
COM [2] 的产生给这个世界增添了几分活力。只有接口!我们的插件需要做的只是实现程序定义的接口。主程序不需要知道插件怎样实现预定的功能,它只需要通过接口访问插件,并提供主程序相关对象的接口。这样一来,主程序与各插件之间的信息交流就变得异常简单。并且,插件对于主程序来说是完全透明的。