Qt工程化项目架构设计实战 - 第1节
一、为什么我们需要工程化架构?
说实话,我刚开始做Qt开发那会儿,根本不懂什么叫架构。
一个mainwindow.cpp能写两三千行,所有逻辑全塞在一起。信号槽满天飞,今天改个按钮,明天崩三个窗口。嗯,这种日子,我相信不少朋友都经历过。
后来我带团队了,发现一个残酷的现实:代码写得好不好,三个月后见分晓。三个月后你自己都看不懂自己写的代码,那这项目基本就废了。
工程化架构的核心目的就三个:
- 可维护性 —— 改一个功能,不会炸掉三个不相关的模块
- 可扩展性 —— 加新功能时,不用重写旧代码
- 可测试性 —— 能单独测某个模块,不用启动整个应用
说白了,架构就是给代码画边界。每个模块管好自己的事,别越界。我在项目中遇到过最典型的反面教材:一个类既处理UI事件,又直接操作数据库,还负责网络通信。这种代码,改起来就像拆炸弹——剪错一根线就全炸了。
二、常见架构模式:MVC / MVP / MVVM
这三种模式,说白了都是在做同一件事:把界面和业务逻辑拆开。但拆法不一样,适用场景也不同。
2.1 MVC —— 最经典,但容易踩坑
MVC分为三部分:
- Model(模型):数据与业务逻辑
- View(视图):界面展示
- Controller(控制器):接收用户输入,更新Model和View
在Qt里,很多人把QWidget既当View又当Controller,结果又回到了大泥球。我个人习惯是:View只负责显示,Controller单独写成一个类。
我的经验:Qt自带的Model/View框架(QAbstractItemModel、QTableView等)其实就是MVC的一种实现。但很多人只用了View,没用好Model,导致数据逻辑散落在各处。
2.2 MVP —— 更适合复杂UI交互
MVP把Controller换成了Presenter。区别在哪?
- View:只负责被动渲染,不包含任何业务逻辑
- Presenter:负责处理用户操作,调用Model,更新View
- Model:数据层,与MVC相同
我曾经在一个医疗设备项目里用过MVP。界面交互极其复杂,一个界面有几十个参数输入。如果用MVC,Controller会膨胀到无法维护。换成MVP后,每个界面对应一个Presenter,逻辑清晰多了。
注意:MVP的缺点是类数量翻倍。每个View都要配一个Presenter。小项目用起来反而累赘。
2.3 MVVM —— Qt的现代选择
MVVM是MVP的进化版。核心思想是数据绑定——View直接绑定到ViewModel的属性,ViewModel变化时View自动更新。
Qt里实现MVVM,主要靠:
- Q_PROPERTY:定义可绑定的属性
- 信号与槽:属性变化时通知View
- QDataWidgetMapper:自动将Model数据映射到控件
我个人现在做新项目,基本都倾向MVVM。原因很简单:写UI代码时不用想着业务逻辑,写业务逻辑时不用管UI长什么样。这种分离感,真的很爽。
三、三种模式对比
| 模式 | 核心思想 | 适用场景 | Qt中的实现难度 |
|---|---|---|---|
| MVC | Model-View-Controller | 简单应用、快速原型 | 低 |
| MVP | View-Presenter-Model | 复杂交互、需要单元测试 | 中 |
| MVVM | View-ViewModel-Model | 数据驱动、大型项目 | 中高 |
四、Qt项目目录结构最佳实践
聊完模式,咱们落地到实际工程。一个Qt项目该怎么组织目录?我见过太多人把所有文件扔在一个文件夹里,找文件全靠搜索。嗯,这种习惯得改。
4.1 推荐目录结构
MyProject/
├── CMakeLists.txt # 顶层构建文件
├── src/ # 源代码
│ ├── app/ # 应用入口
│ │ └── main.cpp
│ ├── core/ # 核心业务逻辑
│ │ ├── models/ # 数据模型
│ │ ├── services/ # 业务服务
│ │ └── utils/ # 工具类
│ ├── ui/ # 界面层
│ │ ├── views/ # 视图(窗口、控件)
│ │ ├── viewmodels/ # ViewModel(MVVM用)
│ │ └── resources/ # 资源文件(qrc、图片等)
│ └── tests/ # 单元测试
│ ├── test_models/
│ └── test_services/
├── third_party/ # 第三方库
├── docs/ # 文档
└── scripts/ # 构建脚本
关键原则:
- 按功能分层,而不是按文件类型。别把所有的.h放一个文件夹,.cpp放另一个
- 每个模块一个子目录,模块内部再按职责细分
- 测试代码与源码分离,但保持相同的目录结构
4.2 命名规范
我习惯的命名方式:
- 类名:大驼峰,如
UserManager - 文件名:与类名一致,如
UserManager.h - 命名空间:按模块划分,如
core::models::User - 信号与槽:信号用
xxxChanged,槽用onXxx
避坑指南:我曾经在一个项目里看到有人把信号命名为 signal1、signal2。三个月后,没人知道这些信号是干什么的。命名一定要自解释,别偷懒。
五、本章知识体系总览
下面这张图,是我自己总结的Qt工程化架构的核心脉络。你可以把它当作一张地图,后续章节都会围绕这些点展开。
这张图把本章的核心内容串起来了。从上到下,先搞清楚为什么要搞架构,再选用什么模式,最后落地到目录怎么组织。后续章节会逐一深入每个细节。
一句话总结:架构不是银弹,但没有架构,项目就是定时炸弹。选对模式,搭好目录,你的Qt项目才能活过三个月。