原文: https://blog.csdn.net/liang19890820/article/details/78134253
简述
要开发一个成功的系统,插件是必经之路。
- 对于小朋友来说,积木是木头塑料,用这些小积木可以拼成房子、动物。
- 对于建筑工人来说,积木是零砖碎瓦,用这些小积木可以构建高楼大厦。
- 对于程序员来说,积木可以看做是插件(更高级一点),用这些小积木可以搭建大系统。
很多人认为插件化很复杂,便将其拒之门外。实际上,从框架的使用角度来看,还是蛮简单的。最难的,其实并不在于框架本身,而在于改变现有开发模式。有一种习惯叫做“墨守成规”,嗯,没错。。。对于程序猿/媛来说,处于这样的状态,和编码机器有什么区别?
| 版权声明:一去、二三里,未经博主允许不得转载。
为什么要引入插件
在软件开发过程中,有一项极具挑战性的任务:构建可满足客户未来需求的产品。
尤其是软件进入扩展/维护阶段,更是如此。但是,在这个阶段,往往会出现很多糟糕的情况:
- 软件设计不合理
- 没有相应的文档
- 团队成员离职(或调离至其他项目组)
- ……
这时,如果一个新的开发人员参与到产品的改进中,那么恭喜!不仅在扩展功能时感到特别吃力,而且还存在破坏现有功能的风险。当然,如果能找到初创团队成员进行协助,那么将很幸福。。。
另外,为现有产品添加新功能的开发成本非常高。因为整个系统需要再次测试,并作为另一个版本发布。
为了解决这些问题,插件出现了!
何为插件
摘自维基百科:
插件(Plugin)是一种电脑程序,通过和应用程序(例如:网页浏览器,电子邮件客户端)的互动,用来替应用程序增加一些所需要的特定的功能。最常见的有游戏、网页浏览器的插件和媒体播放器的插件。
插件化的使命
插件通常被部署为动态库,动态库让插件有许多优点:
- 热插拔(重新加载新的实现,而无需关闭系统)
- 将源代码从应用程序中分离出来
- 便于内部开发人员添加功能
- 使得第三方开发人员对应用程序安全地扩展(附加功能,而不修改核心系统)
然而,有时静态库是插件的最佳选择:
- 对于一些根本不支持动态库的系统(许多嵌入式系统)
- 由于安全性问题,不允许加载外部代码
- 核心系统需要预先加载一些插件,将其静态链接到可执行程序(防止用户意外删除)
当然,一个好的插件系统应该既支持动态插件,又支持静态插件。这样以来,便可以在具有不同约束的不同环境中部署同一套插件系统。
插件化的原理
原则:面向接口编程,而非面向实现编程。
插件都是关于接口的,以插件为基础的系统,其基本概念是:系统可以加载插件,但它不知道任何东西,并且通过一组定义良好的接口和协议与它们进行通信。
在 利用插件扩展Qt应用程序 中,可以看出这一点:
class IPerson
{
public:
virtual ~IPerson() {}
virtual QString name() = 0; // 人有名字
virtual void eat() = 0; // 人需要吃东西
virtual void sleep() = 0; // 人需要睡觉
virtual void doSomething() = 0; // 人还需要干其他事
};
插件的目标是实现 IPerson,业务层的目标是调用 IPerson,业务层不知道 IPerson 具体是如何实现的,而实现者也无需关心业务层是如何调用的。
插件框架的要素
要实现一个插件框架,需要考虑以下要素:
如何注册插件
如何调用插件
如何测试插件
框架要支持自动化测试:包括单元测试,集成测试。插件的生命周期管理
插件的生命周期由插件框架控制,需要考虑以下问题:
- 插件的生命周期如何转换?
- 一旦插件的生命周期发生转变,引用此插件的类是否能得到通知。
插件的管理和维护
对于插件框架而言,这属于基础功能。主要包括:- 为插件提供名称、版本、状态等信息,并可以获取插件列表,记录插件的处理日志等。
- 提供插件加载、启动、停止、卸载等功能。
插件的组装(附加考评要素)
插件的组装是指可以灵活的将多个插件组装为一条链,然后链式的调用。插件的出错处理
当插件在处理过程中发生错误时,最理想的结果是插件的调用停止,并记录相关的日志,另外的插件对此情况做出纠错处理(注意: 不能影响插件框架和其他插件的正常运转)。