[QPlugins] 教程-了解 QPlugins 的整体架构

QPlugins 是 QDAC 开发组奉献给大家一套开源的跨语言插件框架,我希望能它能得到大家的喜欢,并逐渐应用到自己的开发中,用于简化并加快项目的开发进度。

QPlugins 插件框架提供的理念是“插件即服务”,通过各种各样的服务,让程序得以松散耦合和易于扩展。目前核心可以运行在 Win32/Win64/Android/iOS/OSX 平台上,Delphi 和 C++ Builder 下均能正常编译和运行。

在做这个插件引擎之前,我也做过一个仅供自己使用的插件引擎,但我觉得那个引擎并不完美。这个插件引擎也许仍然离完美有很大的距离,但它对于我,包括许多朋友,可能都是一大步。

我们先来看下一 QPlugins 的一个整体框架的示意图:

QPluginsframeworks

整个框架对于程序的核心接口是 IQPluginsManager 这个插件服务管理器接口,它通过 PluginsManager  函数提供一个全局的 IQPluginsManager 接口的实例,而这个 IQPluginsManager 同时实现了 IQService、IQServices、IQPluginsManager、IQNotifyManager 接口(IQNotifyManager 接口未列入核心,但实际上它实现了)。这个实例在单个进程中,它是唯一的,无论你在 DLL、BPL 还是脚本插件中都是指向同一个实例。

当然,有了这个管理器,我们就要分析这个管理器如何去管理插件和插件提供的服务。 QPlugins 框架是一款以服务为核心的插件引擎,所以,它的组织和管理都是围绕着服务来设计的。那么服务来自那里,该如何组织呢?

  1. 服务的来源
    QPlugins 的服务来自于主程序及各个插件。主程序本身会实现一些基础的服务,然后插件会实现自己的一到多个服务功能,然后通过 QPlugins 将其耦合在一起。
  2. 服务的组织
    QPlugins 的服务组织方式有两种,一种是按照 ID 编码,一种是按照路径来组织。QPlugins 重载了 QueryInterface 接口,统一按 ID 直接来查询的 ById 和 QueryInterface 接口的实现。同时,还实现了 ByPath 函数来按路径查询特定的服务。一般来说,两者的主要区别在易用性和识别度上,QueryInterface 和 Delphi 本身结合的更好,你可以直接 PluginsManager as IMyService 这样来请求一个服务,也可以调用系统的 Supports 封装来查询服务是否存在,而 ByPath 可以直接请求类似于 URL 的服务地址,更直观且便于组织。具体如何组织和使用,QPlugins 并不会做特别的限制。
    但请注意, QPlugins 的 IQPluginsManager 实现了一些默认的规则,它创建了三个根结点,我们在后面再加以详细的说明。

在设计 QPlugins 时,因为要跨语言,所以许多系统的接口使用的是 stdcall 规则,如果您实现自己的接口时,不必受此限制。同样的原因,QPlugins 在传递参数时,重新实现了独立的 IQParams 和 IQParam,但如果只是在 Delphi 系统中使用,同样可以不受这些限制。

在设计插件时,我们要注意一些坑:

1、BPL 插件设计的坑
主程序和插件都应该带 vcl 和 rtl 这两个包,否则,窗体会有许多不正常。另外,QPlugins 的一些单元,如果可能做成单独的包引用可能更合理一些。

2、DLL 插件设计的坑
DLL 中的窗口焦点问题,请在主程序和 DLL 中都包含 qplugins_vcl.pas,当然,如果你主程序和插件都带 vcl 和 rtl 两个包编译的话,请忽略此要求。

估计还会有许多坑,大家遇到了多在群中沟通。毕竟我不可能在 Demo 中实现一切,感谢大家关注 QPlugins,接下来我陆续会编写一系列的教程给大家演示如何使用 QPlugins。

 

分享到: