参考强大的群主对插件的10条建议后,,拟对QPlugin的内核实现进行一些调整,以释放出内核各组件更大的定制和重用自由度。
先罗列一下群主的10条大补丸,然后逐一说下想法,大家看了请有想法的也提些建议,在动手前越清晰越好哈。
1、我这里将提供插件管理的核心称之为宿主,它应该是一种及其精简的微内核,唯一的作用就是注册和查询中心,内部维护每个插件的来源和所提供的服务就行。
回:QPlugin的原设计已是如此实现。
2、宿主不需要知道如何去加载每个插件,插件的加载是由提供加载插件加载服务的加载器插件来完成。
回:经思考,对原设计进行微调,在原设计的IServiceManager管理器外再外包一层同接口的管理器,但只管把请求转调用,通过依赖注入真正的服务管理器来进行调度管理,而真正的服务管理器则增加服务调度的扩展点接口,而具体如何实现提供给其它组件实现,框架默认提供一个IPluginManager的插件调度器实现,自定制的调度器可以替换默认的,也可以重用默认的。
3、宿主同样也不知道该如何调度每个插件,插件的调度同样是由提供调度服务的插件来完成。
回:如上第2点,通过增加扩展点接口,服务管理器和插件调度器彻底解耦,而扩展点接口只几个函数,实现定制也是比较容易的。
4、宿主很势利,它允许有实力的插件替换掉老化的插件,也就是所谓服务的可替代性。它根据服务的优先级等参数来决定在调度器查询某项服务时给谁机会。包括调度器和加载器也是一对悲催的角色,虽然很靠近核心,但同样是可替代的插件。当然,有一个例外,宿主自己实际上也是一个调度器,但它唯一干的事就是向自己查询该用那个调度器,然后将控制权交给它。
回:由于服务管理器和插件调度器皆可定制,此项能力可交由插件实现,框架就偷懒下了。
5、插件的加载时间点考虑提供:启动时加载,启动后延迟加载,按需加载和退出前加载四种。
回:原设计支持总是、按需和自动管理方式,想来想去好像基本够用了,框架是按插件配置文件从上到下加载插件的,如果要实现退出前加载处理一些事宜,看起来可以由第一个插件(会最后一个释放)来做就可以了,启动后延迟加载这个也就是空闲时加载,这个好像一运行先把启动就加载的插件加载完后很快就空闲了,在这个时间点上加载好像区别不大,而要另起一个线程来处理好像又耗费了点,所以想来想去,继续保持原设计的吧。
6、插件可以是链式服务的,也可以是单实例的。但即使是链式的,其每个节点也是要遵循可替换原则的。
回:原设计的插件间关系既是并列的,又通过扩展点关系形成树状关系,每个节点可以替换,看起来已符合要求了了。
7、没人规定插件必须DLL或者是BPL,即使规定了,也没人能够强制你遵守,你才是自己源码的主宰。只要实现合适的加载器插件,其他程序、脚本、网页都可以是插件,程序可以写死,但思维一定不要把自己锁死。
回:原设计已通过分离出一个IPluginLoader接口用于载入各种“插件”,具体如何加载由提供者定制Loader即可。
8、插件的注册机制的选择实际上是由加载器插件来决定的,可能从配置文件用导入,也可能直接调用插件的特定接口实现,也可能是在加载插件时,插件自己完成的。
回:可以通过定制插件管理器或插件载入器实现此点的自由处理要求。而原设计提供的默认处理办法是让插件提供服务的描述信息,框架保存此描述信息来进行后续的服务创建和调度。
9、如果可能,插件的加载器最好能实现插件的线上更新,而不需要退出程序。对于有些服务来说,线上更新可以实现不间断服务,这对有些环境很重要。
回:原设计以朴素的手法实现了一个插件的在线更新方案,也好用地,而更高级的在线更新方案可以通过外部插件来实现,就不加肥框架了。
10、接口要有版本化的东西,这对于插件的兼容性来说更重要。一个插件可能用了旧版本的接口,如果可以兼容,提供服务的插件就可以返回老式的接口让他正常工作了。
回:按com的处理就好了,像IDirectDraw1、IDirectDraw2…IDirectDraw7,每个新接口提供有旧接口的服务,但实际上已是不同的接口了。。。
以下为1.7的调整后各组件关系图: