嵌入式OOP架构设计
大家先思考一个问题:
明明一个功能已经调通了,结果改一个小需求,带来的是连锁崩塌;明明一个驱动单独看写得还不错,可一旦放进大项目,立刻各种打架;明明你会写代码、会调外设、会做功能,但就是做不出一个真正能复用、能扩展、能让多人协同推进的大型工程。于是很多人开始怀疑自己: 是不是自己能力不够? 是不是自己代码水平还不行?是不是自己还得再多学几个外设、再多背几个协议?但真相往往不是这个。很多“屎山代码”的诞生,不是因为开发者不努力,也不是因为他不会写驱动,而是因为整个项目从一开始,就没有站在“架构师”的视角去设计。项目不是一点点写烂的,它往往是在最初“先跑起来再说”的那一刻,就已经埋下了后面爆炸的种子。
功能与分层的思考:
一开始,我们盯着的是“功能怎么现”: IIC能不能拉起来; 这个传感器能不能读到值;这个屏能不能亮;这个动作能不能跑出来;这个中断进没进去;这个协议包发没发对。这些当然重要。但问题在于,如果你的思考永远停留在“这个功能能不能实现”,那你就永远只能写好一个点,写不好一个系统。你会发现自己定义结构体,很多时候是凭感觉;你会发现自己封装对象,很多时候是凭经验;你会发现自己做模块边界,很多时候只是“先这么分着试试”。这就是大部分工程后期失控的根源。
因为你从来没有真正问过这些问题: 为什么这个对象要这样定义,而不是那样定义?
为什么这个模块边界在这里,而不是更往下沉到driver? 为什么这个service要直接拿设备数据,而不是依赖平台抽象?为什么今天这个温湿度对象能用,明天换成只有温度的设备时,它还能不能复用? 为什么你写的是“一个能跑的模块”,而不是“一个可以沉淀为公司资产的平台对象”?这才是架构思维和功能思维的真正分水岭。
分层很重要,但“只会分层”远远不够,很多人一提架构,第一反应就是分目录、分层次。APP 一层,Service一层,BSP一层Driver一层。好像目录分出来了,架构就有了。再加几个函数指针,再搞点所谓“面向对象”,就觉得自己已经在做平台化。但这只是架构设计的起点,不是终点。字幕里其实已经把这个问题讲得很透:架构设计远不止目录设计,它至少还包括对象模型设计、数据模型设计、管理模型设计、生命周期设计、依赖设计、配置设计以及扩展机制设计。
对象模型的思考:
分层解决的,本质上只是一个问题:代码放在哪? 它能帮你理清依赖方向,帮你控制调用关系,帮你把变化压缩在局部。但它解决不了另一个更深的问题:对象到底该怎么长。如果没有对象模型,你今天会有一个温度对象,明天有一个湿度对象,后天有一个温湿度对象。它们可能都能工作,但彼此之间没有继承,没有统一基座,没有稳定语义,最后只能不断复制、不断组合、不断变种,工程规模越大,重复越多。这时候,分层没救你。因为真正失控的,不是目录,而是对象本身。真正的平台化,先从“对象模型”开始,很多人对 OOP的理解,还停留在“结构体+嵌入式OOP架构设计函数指针”。
在嵌入式里,对象模型真正重要的地方,不是你语法上像不像C++,而是你有没有建立一个可以贯穿整个工程的统一抽象基座。比如: 一个平台里,device和service能不能共享一套基础父类?这个父类里,能不能抽出name、type、 state、context这些共性?未来一个传感器对象、一个电源管理对象、 一个日志对象,能不能都沿着这条主线有序生长? 你的对象,是不是天然就带着 config runtime context、 state、 ops这些维度?你的多态,是不是靠状态机和配置驱动出来的,而不是靠到处 if else 硬拼出来的?
这才是“对象模型”的价值。它不是为了把代码写得花哨。它是为了让你的工程具备统一的骨架。
没有这层骨架,今天你写AHT21,明天换一个 DHT11,整个service层就得跟着一起抖;有了这层骨架,底层设备可以替换,上层业务几乎无感,因为上层依赖的是抽象,不是某个具体芯片。这也是为什么很多成熟系统里,驱动接口不是随便拍脑袋定的。Linux 里为什么会有一套统一的 file operations? 为什么成熟平台都在强调device、driver、 match、抽象接口? 本质上,都是因为它们先有对象模型,再有具体实现。你以为系统靠函数跑,其实系统是靠“数据” 流起来的,这也是很多人最容易忽略的一层。
分层解决了依赖,对象模型解决了抽象,但真正决定系统能不能协同的,是数据模型。一句话:函数只是数据的处理器,系统真正流动的是数据。当APP 发出一条指令往下走,Service 管理它,Platform转接它,Driver执行它,设备采到一个值再一路往上回传一一这里面最关键的不是“函数有没有调到”,而是: 这个数据以什么形式被封装?哪一层该看到什么数据?APP该不该知道底层寄存器状态?Service该不该直接碰总线细节? Driver该不该暴露设备之外的业务含义? 如果这些问题一开始没想清楚,后面一定会乱。因为每一层都开始关心不该自己关心的东西。
APP 开始知道底层细节,Service开始知道寄存器时序,Driver开始掺杂业务逻辑。到最后,整个工程不是“协作”,而是“互相渗透”。
而好的数据模型恰恰相反: APP 只看它该看的业务数据;Service 只看它该管理的运行状态;Driver只关心设备是否ready、总线是否占用、这次读写是否成功。每一层只处理自己那一份有限而稳定的数据,系统才可能长期稳定。管理模型和生命周期,决定了你的系统是不是“可控” ,很多工程写到后面会乱,还有一个核心原因: 对象有了,但没人真正“组织”它们。
传感器对象创建了,谁来注册?谁决定什么时候 init、什么时候 start、什么时候 process、什么时候stop? 谁负责在不需要时关闭线程、释放资源、进入低功耗? 谁来统一协调设备启动顺序、服务启动顺序、板级资源初始化顺序? 这些都不是“驱动问题”。这些是管理模型和生命周期模型的问题。换句话说:对象回答的是“谁干活”;数据模型回答的是“处理什么”;管理模型回答的是“谁来组织”;生命周期回答的是“这个系统里的器件到底怎么配合着跑起来”。很多人代码写得不差,但项目就是一上规模就崩,本质上不是不会写,而是不会组织。不会组织对象,不会组织数据,不会组织依赖,不会组织生命周期。
所以最后工程看起来像什么?像一群各自能跑的小模块,碰巧被塞进了同一个仓库。但它们从来没有真正构成“系统”。从“能跑”到“能扩展”,这是嵌入式真正的分水岭一个工程真正高级的地方,不是它今天把功能跑通了。而是: 明天换MCU,能不能少改?后天换传感器,能不能无感接入? 再加一个业务功能,能不能不把原有代码冲烂? 多人协作时,边界是不是清晰? 回归测试时,旧功能是不是稳定? 几年以后,新人接手,能不能一眼看懂系统的抽象和生长路径? 这才是架构的价值。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)