上位机开发日记 · 第 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 篇 · 开发流程:六个阶段与验收标准

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

相关推荐
懂点Tech6 小时前
ctfshow misc28:GIF 高度修改解题与脚本实现
开发语言·windows·python
comedate6 小时前
SMLib 的 Examples 导读:PyAPI / SM_API / SMLib 三组示例怎么读
python·cad·smlib·examples·sm_api
云和数据.ChenGuang6 小时前
Python 重写(Override)深度解析:从 MRO 到 super() 的完整机制
java·开发语言·人工智能·python·langchain·1024程序员节
川石课堂软件测试7 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
万化冥合8 小时前
PyBox屏幕键盘如何辅助演示键盘操作?
python·计算机外设
车软学堂8 小时前
从测试转开发,到底要补什么
网络·人工智能·python·功能测试·单片机·车载系统·自动化
天空依然蔚蓝8 小时前
分享一个自动检测网站在线状态的python程序
python·运维开发·1024程序员节
岁月宁静8 小时前
一个 AI 项目从本地到上线,要经过哪些步骤?全流程讲清楚
python·docker·agent
codists9 小时前
《crafting interpreters》阅读笔记:p45-p45
python
曲径海盗10 小时前
【Python 学习第 41 天】for 循环
python·学习笔记·编程入门