插件式软件结构设计(一):构建基于插件式软件平台

 

插件式软件结构设计(一):构建基于插件式软件平台

本文主要简单介绍构建一个插件式软件平台所需要考虑的问题,文中主要介绍基于COM的插件式设计,目前大多数客户端选择基于COM的组件式设计,VC++中的MFC/ATL等框架也对COM做了很好的支持。当然文中所述的解决方案,使用非COM的方式也可以实现,实现原理是一样的。例如,著名的开源项目Miranda,即使用C/C++实现类似本文所述的插件机制。在下篇文章《插件式软件结构设计(二):构建基于DSkinLite的界面解决方案》中将讨论如何插件式软件的界面解决方案。

客户端软件的组件化是目前很多软件设计的选择,其优势有如下几点:

  • 功能模块划分,使软件结构清晰
    很容易想到将根据功能的不同划分成不同的模块。
  • 任务分配容易 有利于团队协作 

    充分利用COM的优势,减少组件之间开发方面的依赖。不同的组件如果有调用关系,则只需要在开发初期约定好IDL接口文件即可。依赖双方可以在互不影响的情况下各自开发,并且在集成测试时不需要做任何改动。

  • 适合敏捷开发,开发过程中模块更新,软件重构容易
    功能模块的划分,使得迭代软件开发更加容易,同时业务变更,产品变更对软件开发的影响较少。

1 组件分类

我们可以将组件分为以下3类: 

 逻辑组件,仅提供一些信息获取等功能,不跟界面打交道,这类组件可以以插件的方式存在,放入插件管理器管理。

提供基础服务的组件,比如网络服务模块,可以置于主程序中

有界面的组件模块,这类组件可以以插件的方式独立存在。

逻辑组件,提供特定的逻辑处理服务。例如:股票相关操作或信息获取接口:

这样根据业务或功能的不同,可以划分不同的功能模块,形成逻辑上相对独立的模块。可以以插件加载入主程序后,其他模块都可以使用此模块提供的功能。

基础服务组件,提供软件的相关基础服务,如网络模块,日志模块。这部分组件可能以独立的dll或者lib出现,并且不放入插件管理器中,以为其提供的功能是基础功能,一般都是需要的,因此不需要将其插件化。如网络模块:

有界面的组件模块,提供相关业务功能服务,同时其带有界面控件处理。这类组件可以以独立的组件或者插件的方式封装。如:

插件式软件结构设计(一):构建基于插件式软件平台

主程序的底边工具栏提供插件服务,插件方可以向其中插入窗口。如

插件式软件结构设计(一):构建基于插件式软件平台为安全组件插入的窗口,由安全组件负责绘制并响应消息,进行逻辑处理。其接口定义如下:

主程序中创建此Panel窗口。代码如下:

放入插件管理器中:

插件方如果想要向此panel插入自己的窗口,则用如下代码调用即可:

2 插件管理器设计

   插件管理器接口定义:

插件式软件结构设计(一):构建基于插件式软件平台

上图提供了一个简单的插件管理器的主要接口定义:

1 IPluginManager 接口定义管理器主要接口函数:

AddObject 用于向插件管理器中加入插件对象。
QueryObject 用于根据相应的插件对象GUID来获取相应接口
RemoveObject 为了支持动态的插件加载,卸载,需要提供RemoveObject从中删除相应的接口。

2  IPluginEvent

                 插件管理器事件通知机制,因为插件之间,主程序某些功能组件与插件之间,可能会有某些功能上存在依赖关系。并且通过简单的控制加载顺序并不能解决问题,如果系统进一步复杂,可能出现相互依赖或者环形依赖,这样按序加载已经解决不了问题。我们必须加入某种在插件加入和卸载时的事件通知机制。

这个功能在实现中采用COM中的连接点方式来实现,类似C/C++函数回调的方式。如果A对其他插件有依赖关系,则使用连接点来和插件管理库的sink连接。

这样当有新的插件进入后,或者有插件被卸载前,那么A将受到相应的连接点通知,如下代码所示:

A可以根据相应的插件对象唯一标识GUID来判断是否是自己感兴趣的对象。

3 插件设计

               插件方(业务逻辑方)需要实现IPlugin 插件接口来实现一个插件。

      IPlugin为插件接口,所有插件必须实现此接口,插件管理器加载相应的COM接口后,会QueryInterface此接口,执行OnLoad来执行插件所需要的初始化操作,在插件被卸载时执行OnUnLoad来执行插件卸载前所需要的反初始化的操作。
       插件方可以根据传递出进来的IPluginManger接口来获取其它接口,并且可以保存此指针,以便在本插件其他地方可以访问。

4 界面插件化

随着功能模块的划分,软件的界面也需要组件化,插件化。这样既可以使得用户可以定制软件界面,也可以使得不同界面代码模块相对独立,对软件维护,软件扩展等有很大帮助。如现在有个股票插件,它可能不仅有逻辑模块,也有界面表现,界面表现如下图所示:

插件式软件结构设计(一):构建基于插件式软件平台

如上图的Tab 类控件,下面的状态栏控件,这类控件需要做成支持动态插入和删除的,同时相关接口放入插件管理器中。这样插件方根据需要向界面中某些控件中插入所需的项目。菜单项也是一个可能需要插件化的模块,因为新的业务插件进来后,可能需要在主面板菜单中加入一些菜单项。

如上面的声明,IContainer为一个container控件,支持向其中加入窗口。这样一个接口对象被置入插件管理器后,其他插件就可以查询到这个接口而向其中插入自己的窗口,并响应消息,处理自己的逻辑。IContainer负责完成插入窗口的高度或宽度调整,整体透明等特性。其他控件的界面绘制由插件自己完成。

5 插件的加载和卸载

插件的加载和卸载中有些地方需要特殊处理并遵循一定的规则。

  • 插件的加载

    根据插件的物理存在,插件分为内置插件,物理独立插件。内置插件指其逻辑上独立,同时又是软件必备的部分,为了加快软件启动速度,这部分可以做成静态lib的方式,直接连接到主程序的exe中。物理独立插件是指以独立dll形式存在的插件,这类插件一般动态载入,会对整个程序的启动速度产生影响。可以使用ini文件配置插件信息,如下:
    [{CEF94D97-2D03-4A0F-9AA0-CF463EF919B1}]
    Name=Tips
    File=../Components/ TipsClient.dll
    Detail= Tips插件负责在消息弹出时弹出提示窗口
    Enable=1

    [{E0C3389D-228B-459E-84D5-BEA15C1E9F0F}]
    Name=数据中心
    File=../Components /datacenter.dll
    Detail=负责处理客户端所需要的数据
    Enable=1

    对于客户端软件来说,启动速度,尤其是软件首次启动速度(系统启动后,第一次启动此软件)是衡量其软件质量的重要标准。对于那些插件较多的软件来说,可以将那些不影响软件启动后显示的插件延迟加入。这样能够使得主界面快速出来,增强软件的用户体验。可以在线程或者Timer中加载插件。

  • 插件的卸载

    插件的卸载需要认真处理,当一个插件被卸载时,其IPlugin接口中的OnUnLoad函数以便插件有机会删除相关资源。同时插件管理器通知所有对此插件感兴趣的插件,如果组件或者插件对此插件有依赖,则相关逻辑需做处理,不能再使用此插件。

         总结:本文主要简单介绍构建一个插件式软件平台所需要考虑的问题,文中主要介绍基于COM的插件式设计,目前大多数客户端选择基于COM的组件式设计,VC++中的MFC/ATL等框架也多COM做了很好的支持。当然文中所述的解决方案,使用非COM的方式也可以实现,原理是一样的。例如,著名的开源项目多协议支持的IM工具Miranda,使用C/C++实现类似本文所述的插件机制。在下篇文章《插件式软件结构设计(二):构建基于DSkinLite的界面解决方案》中将讨论如何插件式软件的界面解决方案。 文章知识点与官方知识档案匹配,可进一步学习相关知识C技能树首页概览113477 人正在系统学习中

来源:haixia8613

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2009年8月2日
下一篇 2009年8月2日

相关推荐