Qt 桌面端架构——七层完整架构与从纯 UI 开始的演化

一句话

Qt 桌面端架构 = 分层 + MVVM 思想 + 业务核心独立:View → ViewModel → Domain/Model → Service → Infrastructure → Utils,从纯 UI 开始逐步把数据、功能、底层拆出来,每个新功能只加对应层,不用推倒重写。


一、完整架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Application

├── UI # 表现层(Qt)
│ ├── MainWindow # 主窗口框架
│ ├── Pages # 多页面
│ ├── Dialogs # 弹窗
│ ├── Components # 通用UI组件
│ ├── Resources # UI资源
│ └── Themes # 主题

├── ViewModel # UI状态与交互逻辑

├── Domain / Model # 核心数据与业务对象

├── Service # 功能服务层

├── Infrastructure # 基础设施层

└── Utils # 通用工具层

每层职责

  1. View(Qt 界面):只负责创建按钮、显示列表、接收鼠标键盘事件、显示状态。不要直接调用 OpenProcess()ReadMemory(),否则以后换 UI 很痛苦
  2. ViewModel:Qt 界面的桥梁,管理当前选择、扫描状态、UI 显示数据
  3. Domain / Model:描述软件里的对象——「软件里的东西是什么」(Image、Project、DownloadTask)
  4. Service:负责动作——「软件能做什么」(ImageService 的 loadImage/saveImage/exportImage)
  5. Infrastructure:负责外部能力(文件系统、数据库、网络、线程、操作系统 API)
  6. Utils:负责项目内部通用的小工具(字符串、时间、转换、数学函数)

线程放哪里

不是 View 开线程:

1
View → ViewModel → Service → ThreadManager → Worker

例如扫描内存:点击扫描 → View → ViewModel → MemoryService → Worker 线程 → 扫描百万地址 → signal 返回结果 → View 刷新。

消息分发在哪里

Qt 用事件循环 + Signal/Slot,不需要自己搞 Win32 的 WndProc/DispatchMessage。如果封装系统层,可以放 infrastructure/MessageDispatcher(负责 Windows 消息、IPC 消息、驱动消息)。


二、Domain 与 Model 的关系

Domain 是把传统 Model 层扩展/升级后的概念,不是简单改名字——Domain 替换了 Model 的位置:

1
2
普通 MVVM:View → ViewModel → Model(只是数据结构、状态保存、DTO)
加入 Domain:View → ViewModel → Application → Domain → Infrastructure

下载管理器例子:

1
2
3
4
5
6
7
8
9
10
// 普通 Model:只是数据
struct DownloadTask { QString url; int progress; };

// Domain:数据 + 规则 + 状态变化
class DownloadTask {
public:
void pause(); void resume(); void cancel();
private:
TaskState state; // 知道什么状态可以暂停、什么可以恢复
};

Service 和 Domain 不是上下级调用关系,而是职责分开:

1
2
3
4
5
6
7
8
9
            View
|
ViewModel
|
Application逻辑
/ \
Domain/Model Service
|
Infrastructure
  • Domain / Model:软件里的东西是什么
  • Service:软件能做什么
  • Infrastructure:外部能力

理解路线五步

  1. 先画 Qt UI → View
  2. 把按钮里面的代码拿出来 → ViewModel
  3. 把数据结构整理出来 → Domain / Model
  4. 把功能操作抽出来 → Service
  5. 把系统调用隔离 → Infrastructure

简单理解:小程序里 Model = 数据;大程序里 Domain = 数据 + 核心对象 + 规则。写成 Domain / Model 是为了表示这一层以前叫 Model,项目复杂了就演化成 Domain——不是两个并列层


三、从纯 UI 开始演化的过程

第一步:先画界面

MainWindow 里有 Button、Label、Table,里面可能先写:

1
button.clicked() { label.setText("Hello"); }

这个阶段只是验证 UI。

第二步:把数据抽出来

1
View(显示)→ ViewModel(保存状态)→ Model

以前 label->setText("100"),变成 viewModel.hp = 100,View 绑定 hp 变化 → signal → label 更新。

第三步:功能分离

1
View → ViewModel → FileService → FileManager

多页面 UI 的展开

1
2
3
4
5
MainWindow(QMainWindow)
├── Navigation(QListWidget/QTreeWidget)
├── HomePage ↔ HomeViewModel
├── SettingsPage ↔ SettingsViewModel
└── DetailPage ↔ DetailViewModel → Domain/Service → Infrastructure

Qt 中实现:QMainWindow + 导航(QListWidget/QTreeWidget)+ 页面容器(QStackedWidget)。

新增功能只加对应层——例如新增「日志分析功能」,只增加 LogPage、LogViewModel、LogEntry、LogService,而不用修改已有页面。


四、DDD 风格的变体

1
2
3
4
5
6
Project
├── presentation/ # 表现层(views / viewmodels / presenters)
├── application/ # 应用层(services / commands / queries / workflows)
├── domain/ # 领域层(entities / value_objects / aggregates / repositories)
├── infrastructure/ # 基础设施层(database / filesystem / network / driver / thread / ipc)
└── common/ # utils / logger / types

依赖方向:Qt UI → Presentation → Application → Domain → Infrastructure。

关键:domain 里不是 Qt,也不是 Windows API;domain 定义接口,infrastructure 提供实现:

1
2
class IMemoryReader { virtual bool read() = 0; };
// Windows 实现 WinMemoryReader.cpp,未来可以有 VTMemoryReader.cpp、DriverMemoryReader.cpp,替换即可

但核心思想不是严格 DDD,而是 Qt 界面先设计 → 数据绑定 → 逻辑抽离 → 底层替换


五、与游戏 ECS 的对照

桌面应用 ECS 游戏
Model Component
Service System
对象实例 Entity
Application 流程 Game Loop
Infrastructure Engine 底层
UI View Renderer / UI System

桌面应用核心是「界面 → 业务 → 数据 → 系统」;游戏 ECS 核心是「实体(Entity)→ 数据组件(Component)→ 系统(System)处理」。


六、适用此架构的软件类型

这套架构的特点:UI 和业务完全分离、底层可以替换、软件可以持续增加页面和功能而不用推倒重写。因此适合绝大多数中大型 Qt 桌面软件

验证工程选择

选择标准:需求不断增加、会用到数据库、多页面、但业务又不算特别复杂。

候选排序(按符合真实开发过程):

  1. 个人知识管理/笔记软件——最符合「不断产生新想法」:今天想到标签就加标签,明天想到全文搜索就加搜索
  2. 数据库客户端——架构最工整,最适合练习分层
  3. IDE——最终形态,但初期复杂度较高

文档型应用(Document-based Application):用户输入少、使用频率高、第一版就能验证架构——文件管理器、图片浏览器、视频播放器、PDF 阅读器、音乐播放器、日志查看器、十六进制查看器。

最终推荐:文件管理器(Explorer Lite)——它几乎覆盖了这套架构的所有层,而且第一版就很自然:

1
2
3
4
5
6
UI:主窗口、目录树、文件列表、详情面板、状态栏
ViewModel:当前目录、选中文件、排序方式、过滤条件
Domain/Model:文件、目录、收藏项、标签
Service:目录扫描、搜索、复制、移动、删除、收藏管理
Infrastructure:文件系统、SQLite、线程、系统 API
Utils:路径、字符串、时间、文件大小格式化

真实需求的来源:零散想法

现实中的需求通常不是「请设计一个数据库管理系统,支持 XXX、YYY、ZZZ」,而更像:

「最近开会总是在纸上画流程,改来改去很麻烦。希望能拖几个方框出来,再用线连起来。连错了或者删错了,希望能撤销。以后可能会有很多图,想保存起来。图大了以后最好可以缩放和拖动画布……」

然后从这几句话自然推导:零散想法 → 需求/功能 → 页面 → ViewModel → Domain/Model → Service → Infrastructure → Utils。

它特别适合验证「架构不是一开始设计完,而是随着想法逐渐成形」这个过程——第一批想法(方框、连线)→ 第二批(保存、打开)→ 第三批(撤销、重做)→ 第四批(缩放、拖动)→ 第五批(模板、颜色、图标)。


与其他线的关系

  • 与 GUI-MVVM(04-系统角色/08):本线是 MVVM 思想在 Qt 桌面端的具体落地——View/ViewModel 的分工、状态变化驱动界面刷新
  • 与系统角色主题:本线的七层(UI/ViewModel/Domain/Service/Infrastructure/Utils)就是系统角色主题在 Qt 桌面端的展开
  • 与领域模型主题:Domain 层就是领域模型在 Qt 应用里的位置——业务对象、规则、状态变化
  • 与 Qt 主题架构线:UI/Themes 目录就是 Qt 主题架构线的落点;主题改变「长什么样」不改变「是什么」
  • 与工程控制主题:「从零散想法逐渐演化」就是过程与流程的演化路线在桌面应用上的实例