动态后端系统
特性
新的软件项目可能很快就会变得非常复杂,而且通常都在严格的时限内开发。因此,重用以前开发系统的一部分对新系统来说既有效又高效。同时,开发通常被拆分到从事项目不同部分的各个团队之间。为了能够重用以前项目的代码,同时将其他团队开发的代码纳入其中,API 被分成了两层:前端和后端。在 Qt 接口框架中,前端 API 被称为 特性,因为通常有一个特定的类负责特定的功能区域,例如 ClimateControl,它控制气候功能区域。
后端
为了正确运行,每个特性都需要与其后端连接。该后端必须实现相应的后端接口。只有这样做,你才能在特性和其后端之间创建一个有效连接。
通常,每个特性只有一个后端接口类,后端需要实现以使特性工作。每个后端接口都源自 QIfFeatureInterface,它提供每个特性都需要的基本函数和信号,例如错误处理。
后端实现被分组在一起,并在一个 Qt 插件 中实现。这使得同时提供多个后端并能够在运行时切换后端变得容易。这些后端插件通过 QtInterfaceFramework 加载。一个插件可以为多个特性提供后端实现;不需要为每个特性创建一个单独的插件。
Qt 接口框架还区分两种类型的后端
- 生产 - 在生产系统中,您希望只运行生产后端。
- 模拟 - 在开发阶段,可能需要使用模拟后端来用于前端开发,直到后端服务可使用。
Qt 接口框架使用一个简单的命名方案来识别插件是否提供模拟或生产后端。每个模拟插件名称中必须包含“simulation”或“simulator”。或者,您也可以在插件的元数据中设置“simulation”键。这对于静态插件尤其有用。
QtInterfaceFramework
QtInterfaceFramework 模块提供所有必要的类来将这些部分粘合在一起。除了提供基类,如 QIfAbstractFeature 或 QIfServiceObject 之外,此模块还提供了 QIfServiceManager,其负责加载必要的后端插件。
QIfServiceManager
QIfServiceManager 是 QtInterfaceFramework 的核心部分,记录所有可用的后端及其导出接口。服务管理器会扫描所有可用的插件及其相关元数据。这个过程使得它能够仅加载功能所需的插件,从而减少启动时间。所有这些信息都以模型的形式收集在服务管理器中,这使得开发者可以选择他们想要使用的插件。
ServiceObjects
ServiceObject 概念保持了功能的灵活性,并在运行时允许在多个后端之间切换。一个 QIfServiceObject 是一个处理句柄,功能使用它来连接到正确的后端接口。此句柄提供查询后端接口的方法,这些接口由 ServiceObject 实现。ServiceObjects 自动包装在插件中,使得可以在多个功能之间共享 ServiceObject,并明确选择为功能实例使用的后端。
根据上图,ServiceObject 是特定插件的句柄。功能A 和 功能B 都使用了相同的 ServiceObject,为 功能A 返回一个 Feature_A_Interface 的实例,为 功能B 返回一个 Feature_B_Interface 的实例。功能类继承自 QIfAbstractFeature;后端接口继承自 QIfFeatureInterface。
ProxyServiceObjects
与代表后端插件句柄的正常 QIfServiceObject 不同,QIfProxyServiceObject 不需要插件才能工作。它可以在应用侧实例化,并且可以填入任何继承自 QIfFeatureInterface 的类。QIfProxyServiceObject 在后端实现不应在一个单独的插件中完成,而应在应用代码库内部完成时非常有用。
ProxyServiceObjects 也用于是其他功能属性的模型。有关详细信息,请参阅 模型。
如何找到功能的后端
通常,所有功能都使用自动发现模式。从 QML,您可以设置 QIfAbstractFeature::discoveryMode 属性;从 C++,您可以调用 QIfAbstractFeature::startAutoDiscovery() 来启动它。此属性请求 QIfServiceManager 所有可用的后端,这些后端实现了您的功能所需的功能接口。然后,管理器选择第一个匹配的后端,并将功能连接到它。QIfAbstractFeature 总是首先请求产品后端;如果不可用,它将回退到一个模拟后端。此行为可以通过 QIfAbstractFeature::discoveryMode 控制它是默认的 QIfAbstractFeature::AutoDiscovery。可以通过 QIfAbstractFeature::discoveryResult 获取这种后端类型。在功能成功加载后端之后,QIfAbstractFeature::serviceObject 属性将持有加载的 ServiceObject,并且 QIfAbstractFeature::isValid 返回 true
。
详细连接顺序
想象有一个名为 ClimateControl 的接口,其详细连接顺序如下
- 在QML中创建了一个 ClimateControl 元素。
- 当 ClimateControl 完成时,调用 QIfAbstractFeature::startAutoDiscovery。
- QIfAbstractFeature::startAutoDiscovery 查询所有可用的后端。
- QIfServiceManager 搜索所有可用的插件及其实现的接口;此搜索只会进行一次。
- QIfAbstractFeature 接受第一个 QIfServiceObject 并连接到相应的接口。
- ClimateControl 元素已准备好使用。
手动分配
如果您不希望您的功能使用自动发现机制,将 discoveryMode 设置为 QIfAbstractFeature::NoAutoDiscovery。之后,该功能将不再搜索后端,您需要手动分配 ServiceObject。
发现模型
对于气候控制等特性,自动发现机制是合适的,因为通常特性和实现该特性的后端之间存在 1:1 的映射。对于更通用的接口,如媒体播放器,这可能不足够:您可以使用此接口控制内置媒体播放器后端,但也可能想要通过蓝牙控制在您的手机上运行的媒体播放器。
为了实现这一点,首先,您需要发现可用的设备,然后将所选设备的 ServiceObject 传递给媒体播放器接口。可以使用 DiscoveryModel 来发现可用的手机。此模型为每个发现的设备提供 ServiceObject。发现模型的概念并不仅限于手机,它可用于所有未通过硬件连接到系统的后端,例如互联网服务或控制多个后排座椅系统。
分区特性
分区是一种为多个点提供单一 API 的标准方式。例如,房屋内的气候控制可以按房间进行,例如客厅和浴室。这些房间充当分区。相同的概念适用于
- 家庭和商用地址簿
- 车队管理系统中的多个车辆
- 汽车中的窗户、镜子、空调
- 等等...
技术上,分区特性由同一特性的多个实例组成,一个顶级实例提供不依赖于分区的 API 和对特定分区实例的访问。该功能需要从 QIfAbstractZonedFeature 继承并实现 createZoneFeature() 以提供分区特定实例。
顶级接口可以提供系统范围内的设置。例如,外界温度和天气预报。相比之下,分区接口提供了每个区域的函数,例如期望的室温。
构建分区特性需要后端接口从 QIfZonedFeatureInterface 继承。此类为后端提供一个枚举可用分区的接口。此接口还包括 QIfZonedFeatureInterface::initialize 方法以初始化任何属性。
© 2024 Qt公司有限公司。本文件中包含的文档贡献的版权属于其各自的拥有者。提供的文档根据自由软件基金会发布的GNU自由文档许可协议版本1.3的规定许可。Qt及其相关标志是Qt公司有限公司在芬兰以及全世界其他国家的商标。所有其他商标均为其各自拥有者的财产。