Neptune 3 UI - 应用架构

Neptune 3 UI使用一个通用的架构和原则来构建所有应用:核心UI架构。

核心UI架构

核心UI架构通过将UI分解成单个UI组件,采用基于组件的架构,以确保组件的可重用性。一个组件将软件元素的功能和行为封装成一个可重用的单元。

基于组件的软件设计比传统的面向对象软件设计具有许多优势,例如

  • 通过重用现有组件来减少上市时间和开发成本。
  • 通过重用现有组件来提高可靠性。

通常,Neptune 3 区分UI原语,如矩形和图像,以及控件,如按钮。要组合多个UI原语和控件,您可以使用面板视图,这是用于布局其他容器或UI类型或控件的特定容器类型。UI原语仅在控件内部使用,因为控件可以设置UI样式。面板和视图之间的区别在于视图与存储器接口,即应用程序的业务层。

应用程序

应用程序通常围绕特定上下文进行设计,往往使用特定服务API的区域,并且还可以依赖于公共服务来了解整体系统状态。核心UI架构的目标是避免UI依赖于这些公共服务的情况;相反,它们应该作为存储实体进行包装。

存储是唯一允许与其他服务实例通信的实体。除了作为服务接口的适配器之外,存储还提供执行干净UI所必需的业务逻辑。因此,UI应仅包含视觉逻辑并排除任何业务逻辑。

反过来,UI本身被分成几个UI元素,其中一些元素可以引用存储;但不允许其他元素。以这种方式严格管理这些依赖关系允许这些组件在项目后期阶段仍然可测试。这种类型的架构还允许开发者在UI的部分进行隔离,并且在该部分独立工作,而无需依赖于服务依赖关系。

示例架构

apps/music/
    stores/
        MusicStore.qml
    views/
        TopView.qml
        BottomView.qml
    panels/
        AlbumArtPanel.qml
        MusicBrowseList.qml
    controls/
        MusicControls.qml
        MusicProgressBar.qml
    Main.qml

基于上图

  • 存储:封装对服务API的访问并包含所需业务逻辑
  • 视图:拥有对存储的引用,为其他组件提供必要信息
  • 面板:其他控件和面板的容器。面板不应依赖存储或视图
  • 控件:无外部数据依赖(除了原语)的可重用视觉元素
  • 助手:一些操作的集合。

存储

store 是一个数据驱动的对象,封装了应用中的业务逻辑;它是唯一使用服务层的 UI 部分。一个 store 可能有子 store,这些子 store 可以进一步扩展到 UI 的子树。理想情况下,一个 store 有一个接口,用于定义待测试的 store 的 API。《视图》(Views)只会看到这个接口,这样它们就不会依赖于具体的 store。继承抽象接口的 store 然后用所需服务的值填充它,并向 UI 提供数据。或者,开发者还可以使用 store 接口,并通过静态模拟数据或自动模拟后端来 feeding UI,后端运行提供所需数据的所需状态。

视图

view 是 UI 面板的一个容器;这是应用内部唯一依赖于 store 的容器。其他 UI 部分需要确保它们不依赖于任何像 view 那样具有依赖关系的 store,以确保这些组件易于测试。

上面的图示是一个音乐应用中简单小部件 view 的例子。这是一个容器,包含音乐控制面板和专辑封面面板。这个 view 从与音乐服务接口的音乐 store 中提取信息,该服务向应用提供一系列歌曲。

面板

panel 是控件和其他面板的容器。通常,一个 panel 是一组支持应用的控件的布局,具有一组功能性,例如下面显示的音乐控制面板。

控件

在这个上下文中,control 是只由应用本身使用的特定于应用的控件。例如,图中上面的播放、上一曲和下一曲按钮。

助手

助手是一个包含计算函数但没有属性的对象。典型的助手是一组 JavaScript 函数,这些函数(如果有必要)可以后来移动到根据应用要求进行的 C++ 代码中。

UI Harnesses

上述体系结构提供给开发者独立工作的能力,而不依赖于某些服务。Neptune 3 UI 的 harnesses 位于测试目录中,也用于单元测试。

在许多大型 UI 项目中,UI 开发者必须运行整个 UI 仅为了看到一个小 UI 组件上的更改。相比之下,UI Harness 允许开发者在开发过程中进行 UI 实时重新加载,例如通过 QmlLive,这可以显著提高他们的工作效率。

以下是一个仪器集群的 UI harness 示例,它使用一些静态数据来模拟特定状态,并且可以独立使用 qmlscene 或 qmllive 运行,而无需运行整个 UI。

// tests/ClusterHarness.qml

import QtQuick 2.8
import QtQuick.Window 2.2

import views 1.0
import stores 1.0

import shared.Style 1.0
import shared.Sizes 1.0

Item {
    id: root
    width: Sizes.dp(1920)
    height: Sizes.dp(720)

    Image {
        anchors.fill: parent
        source: Style.image("instrument-cluster-bg")
        fillMode: Image.Stretch
    }

    // The Cluster View that shows large parts of the cluster
    ClusterView {
        anchors.fill: parent
        rtlMode: root.LayoutMirroring.enabled

        // A mocked cluster store to test the cluster view
        // independently from any services it normally would
        // depend on
        store: ClusterStoreInterface {
            id: dummystore
            navigationMode: false
            speed: 0.0
            speedLimit: 120
            speedCruise: 40.0
            driveTrainState: 2
            ePower: 50

            lowBeamHeadlight: true
            highBeamHeadlight: true
            fogLight: true
            stabilityControl: true
            seatBeltFasten: true
            leftTurn: true

            rightTurn: true
            absFailure: true
            parkBrake: true
            tyrePressureLow: true
            brakeFailure: true
            airbagFailure: true
        }
    }
}

©2019 Luxoft Sweden AB。本文件中所包含的文档贡献的版权属于各自的拥有者。
本提供的文档根据 Free Software Foundation 发布的 GNU Free Documentation License 版本 1.3 的条款进行许可。
Qt 和相关标志是芬兰的 Qt Corporation 或其他国家/地区全球的商标。所有其他商标均为其各自的拥有者。