上位机开发日记 · 第 2 篇 · 架构先行:六层分层与边界

上位机开发日记 · 第 2 篇 · 架构先行:六层分层与边界

阅读时长 :约 5 分钟 · 难度 :入门 · 前置知识 :第 1 篇(定位与三问选型)

本篇回答一个问题:代码该怎么分家。


1. 一个两个月后才会发作的病

项目启动时,你想着"就几个按钮,一个文件够了":

python 复制代码
# main_window.py   ------ 两周后 3000 行
class MainWindow(QMainWindow):
    def on_start_clicked(self):
        self.ser = serial.Serial("COM3", 115200)     # 开串口
        frame = b"\xAA\x55" + cmd + crc               # 拼帧
        self.ser.write(frame)                         # 发指令
        data = self.ser.read(1024)                    # 读数据
        values = struct.unpack("<10h", data[4:24])    # 解包
        for i, v in enumerate(values):                # 洗数据
            self.table.setItem(0, i, QTableWidgetItem(str(v * 0.5)))
        self.curve.setData(ts, values)                # 画图
        open("log.csv", "a").write(",".join(...))     # 存盘

一个月后,需求来了三个:换成网口、加个 CRC 校验、数据要存成二进制。你打开这个文件,发现任何一处修改都可能踩到别的功能------改通讯要动界面代码,改界面要重看协议细节。

这不是代码量的问题,是没有分层:一次点击,从物理层干到了表现层。


2. 六层结构

上位机的标准分工是这样的:

【判断】中间三层(协议、设备、数据)是"看不见的承重墙"。新手容易把注意力全花在最上面那层,但这三层才是决定项目能不能活到第二年的关键。


3. 每一层该做什么、不该做什么

层 该做什么 不该做什么
UI 表现层 控件、事件、绘制、坐标轴、状态显示 不组帧、不碰串口、不做业务计算
应用 / 业务层 流程编排、状态迁移、指令序列、合格判定 不 import 任何 GUI 库
协议 / 通讯层 组帧解帧、校验、超时重传、心跳 不关心数据含义,不知道界面上是什么
设备抽象层 统一 open / close / read / write 接口 不实现协议细节,不做业务判断
数据层 缓存、格式、落盘、回放、时间戳 不判断"这个值合格吗"(那是业务层的事)
基础设施 日志、配置、异常体系、打包脚本 不掺业务逻辑

关键理解:"不该做什么"比"该做什么"更重要

以协议层为例。它解出一帧数据后,只知道"第 3 到第 5 字节是一个 16 位小端整数,物理量纲是 mV",它不该知道这个值代表"驻波比"还是"增益",更不该知道"超过 2.0 就要变红"。

因为一旦协议层知道了业务含义,换一个仪器型号时,你就要同时改协议层和业务层------耦合就是这样长出来的。

同理,设备抽象层的存在意义是:上层代码写的是 dev.read(),不管是串口、TCP 还是 VISA 后端,上层一行都不用改。 这是第 4、5 篇要重点打的底子。


4. 一条硬检验标准

分层做得好不好,不需要凭感觉。用这一条检验:

把 UI 层整个删掉,其他层能否照常跑通并跑出数据?

  • 能 → 分层是对的。业务逻辑在正确的位置,界面只是"显示器"。
  • 不能 → 说明业务逻辑漏进了界面层。这是最难还的债,趁早拆。

【判断】实操建议:写一个 main_cli.py,不用任何图形界面,纯命令行跑通"连接 → 采集 → 存盘"全流程。它既是分层检验器,也是第 1 篇那个"设备模拟器"的雏形。


5. 三种常见的分层反模式

反模式 症状 后果
上帝窗口 所有逻辑写在 MainWindow 的方法里 无法单测,无法复用,无法换界面
深入调用 UI 层直接调 serial.write() 换通讯介质要改界面代码
数据回灌 数据层反调界面更新显示 循环依赖,界面卡死时整条链断掉

【判断】第三种最隐蔽。正确方向永远是单向的:数据从下往上流,指令从上往下流,绝不允许下层回头调用上层。


6. 分层带来的实际收益

收益 具体表现
可测试 协议层、业务层可以脱离硬件跑单元测试(见第 12 篇)
可替换 换仪器、换介质、换界面框架,只动一层
可并行 硬件没到位时,用模拟器先把上层写完
可维护 定位问题只需问"这是哪一层的事"

第 5 篇那套解帧器代码,之所以能直接拿来用,就是因为它是纯函数式的协议层代码------喂字节进去,吐帧出来,不依赖任何界面和设备。


7. 本篇小结

记住这一条 说明
六层各司其职 UI、业务、协议、设备、数据、基础设施
边界靠"不该做什么"划 协议层不知道业务含义,数据层不做合格判定
分层硬标准 删掉 UI 还能跑通,就是对的
数据流单向 数据向上流,指令向下流,绝不回头
承重墙在中间三层 协议、设备、数据决定了项目能活多久

8. 动手练习

给你的项目画一张分层草图,然后回答:

  1. 你现在写的代码,分别落在哪一层?(如果有代码落不进任何一层,说明边界还没划清)
  2. 你现在有没有"UI 层直接开串口"的地方?有的话标记出来,那是第一批要重构的目标。
  3. 如果明天要把串口换成网口,你需要改几个文件?理想答案是一个都不改。

上一篇 :第 1 篇 · 上位机到底在解决什么问题

下一篇 :第 3 篇 · 开发流程:六个阶段与验收标准

------从"分层"到"分步":先做什么、后做什么,每步怎么算做完。

相关推荐
李日华大战鸡红2 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
外收内放4 小时前
Python基础语法练习题(57-58)
开发语言·python
朝朝辞暮i4 小时前
VLA 系统学习第 3 课:从一次机器人示范,到真正送进神经网络的 Batch
人工智能·python·深度学习·神经网络·vla
小鹿的周先生5 小时前
第11章-Structured-Output
开发语言·人工智能·python
梦在远山后5 小时前
通过 WSS 让 Server 安全调用 Desktop 本地工具(下01):Ticket、人工确认、幂等与断线对账
python·langchain·agent
泡海椒5 小时前
JQuick-Excel 实战:FORMAT 管理日期与数字的 Excel 显示
开发语言·python·excel
学掌门6 小时前
老司机带你十分钟入门Python!
开发语言·python
YEGE学AI算法7 小时前
Python实现Log-Mel Fbank:分帧、加窗、FFT与Mel滤波器组
python·语音识别·fbank·log-mel·音频特征
甜到心里的蛋糕7 小时前
Playwright 无头浏览器自动发布 CSDN 图文草稿的实践(持久化 profile + 图床直传)
运维·python·playwright·爬虫自动化·博客运营