02-Qt桌面端架构
Qt 桌面端架构——七层完整架构与从纯 UI 开始的演化
一句话
Qt 桌面端架构 = 分层 + MVVM 思想 + 业务核心独立:View → ViewModel → Domain/Model → Service → Infrastructure → Utils,从纯 UI 开始逐步把数据、功能、底层拆出来,每个新功能只加对应层,不用推倒重写。
一、完整架构
1 | Application |
每层职责
- View(Qt 界面):只负责创建按钮、显示列表、接收鼠标键盘事件、显示状态。不要直接调用
OpenProcess()、ReadMemory(),否则以后换 UI 很痛苦 - ViewModel:Qt 界面的桥梁,管理当前选择、扫描状态、UI 显示数据
- Domain / Model:描述软件里的对象——「软件里的东西是什么」(Image、Project、DownloadTask)
- Service:负责动作——「软件能做什么」(ImageService 的 loadImage/saveImage/exportImage)
- Infrastructure:负责外部能力(文件系统、数据库、网络、线程、操作系统 API)
- 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 | 普通 MVVM:View → ViewModel → Model(只是数据结构、状态保存、DTO) |
下载管理器例子:
1 | // 普通 Model:只是数据 |
Service 和 Domain 不是上下级调用关系,而是职责分开:
1 | View |
- Domain / Model:软件里的东西是什么
- Service:软件能做什么
- Infrastructure:外部能力
理解路线五步
- 先画 Qt UI →
View - 把按钮里面的代码拿出来 →
ViewModel - 把数据结构整理出来 →
Domain / Model - 把功能操作抽出来 →
Service - 把系统调用隔离 →
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 | MainWindow(QMainWindow) |
Qt 中实现:QMainWindow + 导航(QListWidget/QTreeWidget)+ 页面容器(QStackedWidget)。
新增功能只加对应层——例如新增「日志分析功能」,只增加 LogPage、LogViewModel、LogEntry、LogService,而不用修改已有页面。
四、DDD 风格的变体
1 | Project |
依赖方向:Qt UI → Presentation → Application → Domain → Infrastructure。
关键:domain 里不是 Qt,也不是 Windows API;domain 定义接口,infrastructure 提供实现:
1 | class IMemoryReader { virtual bool read() = 0; }; |
但核心思想不是严格 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 桌面软件。
验证工程选择
选择标准:需求不断增加、会用到数据库、多页面、但业务又不算特别复杂。
候选排序(按符合真实开发过程):
- 个人知识管理/笔记软件——最符合「不断产生新想法」:今天想到标签就加标签,明天想到全文搜索就加搜索
- 数据库客户端——架构最工整,最适合练习分层
- IDE——最终形态,但初期复杂度较高
文档型应用(Document-based Application):用户输入少、使用频率高、第一版就能验证架构——文件管理器、图片浏览器、视频播放器、PDF 阅读器、音乐播放器、日志查看器、十六进制查看器。
最终推荐:文件管理器(Explorer Lite)——它几乎覆盖了这套架构的所有层,而且第一版就很自然:
1 | UI:主窗口、目录树、文件列表、详情面板、状态栏 |
真实需求的来源:零散想法
现实中的需求通常不是「请设计一个数据库管理系统,支持 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 主题架构线的落点;主题改变「长什么样」不改变「是什么」
- 与工程控制主题:「从零散想法逐渐演化」就是过程与流程的演化路线在桌面应用上的实例
