资讯动态

用伪代码描述模式切换:状态转换、边界梳理与实战写法

发布时间:2026/10/9 4:49:38 来源:尧图企业网站定制
1. 模式切换需求的“第一公敌”自然语言说不清状态我先说个真实体验。在接手过的不少项目和方案里“模式切换”这四个字出现频率极高——无线设备的胖瘦模式切换、驱动软件的语言界面切换、照明系统的情景模式切换、设备的运行/配置模式切换。每次需求方开口都是同一句话“就加个模式切换嘛很简单。”但真正动手做的时候你会发现几乎所有问题都出在“模式切换”这四个字上切到什么状态、由谁触发、切换瞬间旧状态怎么处理、非法切换怎么办、切换失败回滚到哪。这些用大白话聊大家都能聊个大概齐可一旦要落地实现就发现每个人都理解得不太一样。项目经理理解的切换是界面上一个按钮开发理解的切换是一堆if/else测试理解的切换是十几条用例。语言太含糊代码太啰嗦这时候伪代码的价值就出来了——它卡在中间那一层用近乎结构的语言把切换逻辑定死谁看了都得承认“对就是这个意思”。这篇文章我想专门聊聊一个话题如何用伪代码把各种模式切换场景描述清楚。不是讲某一种特定语言而是讲伪代码本身怎么组织、怎么分支、怎么写状态流转、怎么描述边界再配上几个真实的模式切换案例让你能直接抄。适合看的人包括要写设计文档和方案说明的工程师、需要把算法或流程讲清楚的老师/学生、做嵌入式或无线设备维护的现场人员、以及任何被“模式切换”需求折磨过的人。模式切换的本质说穿了就是状态转换。而伪代码擅长干的事恰好就是描述状态转换。它不需要你纠结某一行语法能不能编译不需要你考虑内存分配只需要你把“什么条件下做什么事、做完之后变成什么状态”讲明白。2. 先梳理模式切换的完整边界再动笔写伪代码很多人写伪代码上来就写if(条件) mode 0写得飞快一周后回来看不知道自己在写什么。我自己的习惯是动手前先把模式切换的所有边界条件列清楚伪代码才写得快。2.1 一个实用的模式切换分析清单先说结论任何模式切换需求动手前至少要回答下面这些问题有哪几种模式每种模式的正式名称和编号是什么当前模式的“初始状态”是什么上电/启动之后进入哪个模式触发切换的事件有哪些是按键、串口命令、网络指令、还是自动条件切换过程中是否需要保存当前模式的现场比如参数、临时数据切换失败怎么办是保持原模式还是进入一个错误/降级模式是否有非法切换比如从模式A不允许切到模式C这种请求如何处理模式切换之后哪些资源要重新初始化哪些要关闭是否允许多个触发源同时发起切换如何仲裁这些问题的答案直接决定伪代码里的判断条件分支怎么写。你漏掉一项后面实现的时候就得补一堆补丁。我见过最典型的翻车现场是这样的一台设备有“配置模式”和“运行模式”切换条件写得清清楚楚但需求里没提“当前模式正在执行关键任务时收到切换指令怎么办”。结果就是调试现场出现设备在写入参数的过程中被切到运行模式参数写了一半设备直接跑飞。伪代码里加一行“if 当前处于写参数状态 then 拒绝切换”就能解决的问题因为没提前梳理生生变成一次现场事故。2.2 把状态转换画成一张表再编码对于模式切换这种多状态场景我强烈建议先做一张模式转换表把“源状态”“触发事件”“目标状态”“动作/副作用”填进去然后照着表来写伪代码。表格可以避免你在伪代码里漏掉某个分支也方便后面评审。假设一个简单的设备有三态待机模式、配置模式、运行模式。合法转换有这些源模式触发事件目标模式切换动作待机模式收到进入配置指令配置模式加载配置参数初始化配置接口待机模式收到启动运行指令运行模式初始化外设进入主循环配置模式收到退出配置指令待机模式保存参数关闭配置接口运行模式收到停止指令待机模式停止任务释放资源配置模式收到运行指令运行模式加载新配置初始化运行环境运行模式收到配置指令配置模式暂停任务打开配置接口把这张表定下来之后伪代码的骨架基本就出来了。你不需要在写代码的时候拍脑袋想“哦这里还能切一下”表里没有的转换一律视为非法切换。3. 伪代码描述状态转换的三种写法以及各自的适用场合有了上面的转换表接下来就是怎么写的问题。伪代码没有统一标准但描述模式切换市面上常见的写法大致有这三种顺序分支型、事件循环型、状态表驱动型。我分别说清楚它们的写法、优缺点以及什么情况下选哪种。3.1 顺序分支型最简单适合单任务小逻辑这种写法最接近普通人的思维就是一层一层if/else嵌套。优点是直白缺点是模式一多、嵌套深了以后可读性暴跌。// 顺序分支型模式切换伪代码 当前模式 待机模式 收到指令(指令内容) { if 当前模式 待机模式 { if 指令内容 进入配置 { 加载配置参数() 初始化配置接口() 当前模式 配置模式 } else if 指令内容 启动运行 { 初始化外设() 当前模式 运行模式 } else { 忽略指令() // 待机模式不接受的指令 } } else if 当前模式 配置模式 { if 指令内容 退出配置 { 保存参数() 关闭配置接口() 当前模式 待机模式 } else if 指令内容 启动运行 { 加载新配置() 初始化运行环境() 当前模式 运行模式 } else if 指令内容 设置参数 { 更新配置参数(指令内容) } else { 忽略指令() } } else if 当前模式 运行模式 { if 指令内容 停止 { 停止任务() 释放资源() 当前模式 待机模式 } else if 指令内容 进入配置 { 暂停任务() 打开配置接口() 当前模式 配置模式 } else { // 运行模式下的业务指令处理 执行业务逻辑(指令内容) } } else { 报错(未知模式) } }这段伪代码一看就懂对3~4种模式、每次事件只做一件事的小系统完全够用。但你要是系统里有8种模式、每个模式能响应10种事件这段代码就没法看了——嵌套层级会变得极深加一种模式要动五六处地方。3.2 事件循环型适合持续运行、事件驱动的场景很多设备不是“收到指令才动”而是“永远在跑循环轮询各种事件”。这种场景下伪代码的主结构是一个while循环模式切换在循环内部处理。它的优势是贴合实时系统的真实运行方式缺点是写起来容易把业务逻辑和切换逻辑混在一层。// 事件循环型模式切换伪代码 当前模式 待机模式 while (系统运行中) { event 等待或轮询事件() // 按键、串口、定时器、网络消息都算事件 切换与处理分析(event) { if event 按键短按 { if 当前模式 运行模式 { 暂停任务() 打开配置接口() 当前模式 配置模式 } else if 当前模式 配置模式 { 保存参数() 关闭配置接口() 当前模式 运行模式 } } if event 串口指令 { 解析串口数据(指令) if 当前模式 配置模式 { 按指令处理配置事务() } else { 回复(当前模式不允许此操作) } } // 其他事件处理 } 模式特有业务处理() { if 当前模式 运行模式 { 执行运行任务分钟片() } else if 当前模式 配置模式 { 刷新配置界面状态() } } }这种写法有一个隐藏陷阱模式切换判断分散在事件处理的各个角落里一旦你忘了在某个事件分支里判断当前模式就可能出现“配置模式下还执行着运行动作”的问题。我的习惯是所有模式判断尽可能集中在一个处理函数里不要在多个地方重复判断模式否则后面排查模式相关bug会非常痛苦。3.3 状态表驱动型模式一多这是最优解如果模式超过5个、事件超过5类顺序分支和事件循环都会变得很臃肿。这时候业界通用的做法是状态表驱动把“哪个模式遇到哪个事件执行什么动作、切到什么模式”提取成一张二维表。伪代码写出来的不再是嵌套判断而是查表。// 状态表驱动型模式切换伪代码 定义事件类型 E_进入配置、E_退出配置、E_启动运行、E_停止、E_设置参数 定义模式编号 S_待机、S_配置、S_运行 定义状态表transition[模式][事件] transition[S_待机][E_进入配置] {动作: 加载配置参数初始化配置接口, 下一模式: S_配置} transition[S_待机][E_启动运行] {动作: 初始化外设, 下一模式: S_运行} transition[S_配置][E_退出配置] {动作: 保存参数关闭配置接口, 下一模式: S_待机} transition[S_配置][E_启动运行] {动作: 加载新配置初始化运行环境, 下一模式: S_运行} transition[S_配置][E_设置参数] {动作: 更新配置参数, 下一模式: S_配置} transition[S_运行][E_停止] {动作: 停止任务释放资源, 下一模式: S_待机} transition[S_运行][E_进入配置] {动作: 暂停任务打开配置接口, 下一模式: S_配置} // 表格里没有的组合均为非法切换统一忽略或报错 主流程(event) { if transition[当前模式][event] 不存在 { 记录错误(非法切换: 模式 当前模式 事件 event) return } 执行动作(transition[当前模式][event].动作) 当前模式 transition[当前模式][event].下一模式 }这种写法的优势非常突出要加一种模式只需要在表里加一行要看所有合法状态扫一眼表就行切换逻辑错误也只可能出现在表定义里而不会散落在大量if/else中。我参与过的项目里凡是模式超过5种的最后几乎都改成状态表驱动。如果你现在准备新写一个模式切换逻辑我建议直接上状态表别犹豫。4. 对号入座三个真实的模式切换场景伪代码拆解理论说了一堆下面用三个具体场景把前面的写法串起来。这三个场景分别对应热词里提到的“AP胖瘦模式切换”“驱动调试软件语言切换”“设备模式切换”我把每个场景的伪代码都给出一个可直接参考的版本。4.1 无线AP胖模式和瘦模式切换嵌入式设备现场配置场景胖模式Fat AP和瘦模式Fit AP是无线网络设备里特别典型的模式切换需求。胖模式下AP独立工作、自己管配置瘦模式下AP被AC集中管控AP自己的配置功能关掉。实际现场操作里很多AP默认瘦模式需要切到胖模式做独立组网这个切换一般通过设备上预留的按键、串口或专用配置页面完成。伪代码可以这么写// AP胖瘦模式切换伪代码 当前角色 瘦模式(Fit) 保存配置标记 false 循环 { if 读取按键 模式切换键长按5秒 { 提示用户(即将切换工作模式切换后设备将重启) if 当前角色 瘦模式 { 备份当前配置到持久化存储() 写入启动标志 胖模式 重启设备() } else if 当前角色 胖模式 { 写入启动标志 瘦模式 恢复出厂配置中的受管参数() 重启设备() } } if 串口收到切换指令 switch-to-fat { 校验指令权限() 写入启动标志 胖模式 设置需重启标记 true } if 串口收到切换指令 switch-to-fit { 校验指令权限() 写入启动标志 瘦模式 设置需重启标记 true } if 需重启标记 true { 完成当前事务保存() 执行重启() } }这段伪代码里的关键点其实是“重启设备”这个动作。很多AP的模式切换不能热切换必须重启才能生效所以伪代码里把“写入启动标志”和“重启”分开处理中间留出了保存事务的空间。你在写类似场景时一定要确认目标设备到底支持热切换还是只能冷切换这决定了伪代码要不要在切换动作后面加上“需重启”这一步。我见过有人照着“改一个寄存器就能立即切换”的思路写伪代码结果设备根本做不到调试时全场傻眼。4.2 英文驱动软件切换中文界面软件本地化的模式切换细节这个场景看着很简单但里面有个容易踩的坑语言切换不只是一句“改个变量”它涉及界面刷新、字体重载、菜单重建、甚至部分控件的尺寸调整。伪代码里如果只写“语言中文”那这个伪代码就是个废的——它漏掉了模式切换后必须执行的配套动作。// 软件界面语言切换伪代码 当前语言 英文(默认) 函数 切换语言(新语言代码) { if 新语言代码 当前语言 { 返回(无需切换) } 检查新语言的翻译资源文件是否存在() if 资源文件缺失 { 弹窗提示(语言包不存在保持原语言) 返回 } 是 保存当前界面状态(): 记录当前窗口位置 主窗口坐标 记录当前焦点控件 焦点控件ID 否 保存当前界面状态无法完成(): 弹窗提示(有未保存的修改请先处理) 返回 当前语言 新语言代码 重新加载菜单文本() 重新加载工具栏图标和提示文本() 重建当前打开的所有对话框() 按语言特性调整字体和控件尺寸() // 中文通常需要更高的行高 恢复窗口位置和焦点() 写入配置文件(语言 新语言代码) 提示用户(切换成功部分界面将在重启后完全生效) }4.3 从启动到运行的设备工作模式切换多个起点与中断处理有的设备不是简单的收到指令才切换而是从上电开始就一路切换启动模式→初始化模式→就绪模式→运行模式中间还可能插入休眠模式、故障模式。这种伪代码更复杂的地方在于“启动过程本身就是一个模式切换序列”同时还要考虑故障打断。// 设备工作模式全生命周期伪代码 当前模式 启动模式 上电流程() { 硬件自检() if 自检失败 { 当前模式 故障模式 记录故障码(硬件自检失败) return } 加载配置() if 配置文件损坏 { 使用默认配置() 记录警告(配置损坏使用默认参数) } 当前模式 初始化模式 初始化外设1() 初始化外设2() 初始化通信接口() if 任一初始化超时 { 当前模式 故障模式 记录故障码(初始化超时) 进入看门狗等待复位() return } 当前模式 就绪模式 通知上位机(设备就绪) } 主循环() { if 收到启动命令 and 当前模式 就绪模式 { 启动业务任务() 当前模式 运行模式 } if 收到停止命令 and 当前模式 运行模式 { 停止业务任务() 保存运行参数() 当前模式 就绪模式 } if 收到休眠命令 { 保存全部上下文() 关闭非必要外设() 当前模式 休眠模式 } if 当前模式 运行模式 { 执行周期业务() 检查运行异常() if 检测到严重异常 { 当前模式 故障模式 紧急停止输出() 记录故障码() 触发看门狗复位() } } }这个场景里最容易被忽略的是故障模式。很多初版伪代码只有正常切换路径没有异常路径结果真实设备一跑就露馅。伪代码写得好的一个重要标准就是正常路径覆盖完整异常路径和非法路径也有明确归处。5. 直接把伪代码改成可运行代码一个从设计到编码的转化实例伪代码写得好不好有一个试金石能不能顺畅地翻译成真实代码。尤其是模式切换逻辑翻译过程中若需要大改结构说明伪代码的结构有问题。下面用一个完整的例子来演示从伪代码到C语言代码的转化过程。5.1 场景设定多模式设备的状态机实现设设备有三个输入事件按键事件、定时器事件、串口数据事件。设备有三种模式空闲模式、采集模式、传输模式。要求如下空闲状态按按键进入采集模式采集模式下定时器每100ms采集一次数据收到串口“停止采集”指令回到空闲模式空闲状态收到串口“传输数据”指令进入传输模式传输完成后自动回到空闲模式。5.2 先写伪代码定死逻辑事件按键按下、定时器超时、串口收到停止采集、串口收到传输数据、传输完成 模式空闲模式、采集模式、传输模式 状态表 空闲模式 按键按下 动作[启动采集定时器] 下一模式[采集模式] 空闲模式 串口传输数据 动作[开始传输数据] 下一模式[传输模式] 采集模式 定时器超时 动作[采集一次数据并存储] 下一模式[采集模式] 采集模式 串口停止采集 动作[停止采集定时器] 下一模式[空闲模式] 传输模式 传输完成 动作[清理传输资源] 下一模式[空闲模式] 其他组合 忽略5.3 再转成C语言实现typedef enum { MODE_IDLE, MODE_ACQUIRE, MODE_TRANSMIT } device_mode_t; typedef enum { EVT_BUTTON, EVT_TIMER, EVT_STOP_ACQ, EVT_START_TX, EVT_TX_DONE, EVT_INVALID } event_t; device_mode_t current_mode MODE_IDLE; static void do_start_acq_timer(void) { /* 启动定时器 */ } static void do_stop_acq_timer(void) { /* 停止定时器 */ } static void do_sample_data(void) { /* 采集一次 */ } static void do_start_tx(void) { /* 开始传输 */ } static void do_clean_tx(void) { /* 清理资源 */ } void handle_event(event_t evt) { switch (current_mode) { case MODE_IDLE: if (evt EVT_BUTTON) { do_start_acq_timer(); current_mode MODE_ACQUIRE; } else if (evt EVT_START_TX) { do_start_tx(); current_mode MODE_TRANSMIT; } else { /* 非法事件忽略 */ } break; case MODE_ACQUIRE: if (evt EVT_TIMER) { do_sample_data(); /* 保持采集模式 */ } else if (evt EVT_STOP_ACQ) { do_stop_acq_timer(); current_mode MODE_IDLE; } else { /* 忽略 */ } break; case MODE_TRANSMIT: if (evt EVT_TX_DONE) { do_clean_tx(); current_mode MODE_IDLE; } else { /* 忽略 */ } break; default: /* 未知模式恢复正常态 */ current_mode MODE_IDLE; break; } }对比一下伪代码和C代码就能看出伪代码里的“事件”对应C代码里的枚举“下一模式”对应变量赋值“动作”对应函数调用。转换过程不需要拍脑袋加任何逻辑只需要做机械翻译这就是一份合格伪代码的验证标准。这里附带一个实战中常见的问题事件有可能同时到达比如定时器刚触发串口指令也到了。单线程裸机编程里这通常表现为中断嵌套需要你决定事件优先级。伪代码阶段就要把这些写清楚比如“定时器事件优先级高于串口事件”否则写C代码时中断优先级配置会让人非常头大。6. 在WPS Word里把伪代码排得像回事字体、缩进和格式设置前面所有内容都在讲伪代码怎么写现在说一个非常接地气的话题——很多人在WPS Word或Word里写伪代码结果排版丑得不行缩进乱、字体不统一、看起来像一段普通的正文。我在这上面被折腾过不少次说几个实践经验。6.1 字体选择要贴近代码风格伪代码虽然不是真正的代码但它有代码的要素关键字、变量名、缩进、符号。排版上最好按代码的风格来处理核心就是等宽字体。我最常用的组合是等宽英文字体Consolas 或 Courier New必要时用中文语境也凑合的开源等宽字体比如思源等宽。中文字体在WPS里直接设置等宽字体时中文会回退到宋体或默认字体观感尚可。如果你在意可以把中文字体单独设为“等线”或“微软雅黑”保持中文字符的清晰度。字号建议正文12磅伪代码统一用小5号10.5磅行距设成固定值18磅左右避免伪代码行与行之间太挤或者太松。6.2 建立一个专门的“伪代码”段落样式这是最省事的方法。我是在WPS里这样做的新建一个段落样式命名为“伪代码”。字体设为Consolas西文字体和中文字体分别指定。段落左缩进设为0.74厘米或1厘米代表每层缩进的基础单位后面手动加空格或制表符时都基于这个基准。行距设为“固定值18磅”关掉“如果定义了文档网格则对齐到网格”不然行距会被网格顶乱。段前段后各设6磅让伪代码块与正文之间有明显间隔。背景色基本不加。如果确实想要代码块效果可以给整个段落加个浅灰底纹但我个人觉得白底黑字在技术文档里最稳妥打印也正常。6.3 缩进和换行不要用全角空格这是一个非常隐蔽的坑。在中文输入法状态下按空格输入的是全角空格两个全角空格看着挺齐实际上在等宽字体下宽度不一致会导致伪代码的对齐在视觉上歪掉。写伪代码时我建议把输入法切换到英文半角状态缩进统一用“Tab”或“两个半角空格”。给出的伪代码可以单行放下的尽量不换行。万一某行太长要换行下一行缩进要比上一行多一层同时行首用“|”或“→”之类的续行符标注让人一眼看出这行是上一行的延续。不过技巧是伪代码本来就不该写太长一行超过80个字符就说明逻辑该拆分或变量名该缩短了。6.4 直接在WPS里录制的实操步骤为了不让大家觉得我在讲空话我给出在WPS Word里的具体操作步骤选中已经写好的伪代码段落。在“开始”选项卡里点“样式”右下角的小箭头选择“新建样式”。名称输入“伪代码”将基准样式设为“正文”。点击左下角“格式”按钮选“字体”西文字体选Consolas中文字体选等线大小为小五。再次点“格式”按钮选“段落”在对齐方式里选“左对齐”缩进里的左缩进设为1字符行距选固定值18磅段前段后各6磅。保存样式之后所有伪代码段落直接点这个样式就行。另外如果你要贴的伪代码里有大量的缩进和对齐可以在Word/WPS里插入一个1×1的表格把伪代码放进表格单元格里表格边框设成无。这样伪代码块会被当成一个整体不受页面分页影响也不会被正文段落格式干扰。这个办法适合较长的伪代码。7. 伪代码的正确性验证拿“100到200之间的素数输出”做一次完整推演讲了这么多模式切换现在换一个完全不同的经典问题来收尾这一段——判断一个伪代码写得对不对、能不能直接用。就用热词里提到的这个经典算法题输出100到200之间的所有素数。这个题目虽然简单但正好能说明伪代码的几种表达方式之间的差异以及如何验证伪代码的正确性。7.1 用三种描述方式表达同一个算法这个题目的标准解法是遍历100到200之间的每个整数判断它是否为素数只能被1和自身整除是则输出。有三种常见表达方式。方式一流程图流程图的画法是开始→初始化i100→是否i200是则结束→否初始化j2→是否j i且i能被j整除→是则i加1并回到判断i的范围否则j加1再重复内层判断→内层循环结束后检查j是否达到i是则输出i。流程图适合给人讲解“流程走得通不通”它的优点是直观缺点是写起来费纸而且复杂逻辑画出来像蜘蛛网。执行力强的团队很少用流程图指导编码更多用来做PPT汇报。方式二NS图NS图Nassi-Shneiderman图用嵌套矩形描述逻辑每个矩形块表示一个处理步骤或判断。它的好处是强制结构化没有箭头跳转缺点是绘制工具支持度差大部分情况下是手工慢慢画投入产出比很低。题目的NS图画出来就是外面一个大矩形“从100到200遍历”里面再嵌一个内层循环矩形“判断是否为素数”再嵌一个输出矩形。方式三伪代码这是我在文档里和给团队评审时最常用的表达方式。// 输出100~200之间的素数 for i 100 to 200 { 是否为素数 真 for j 2 to (i-1) { if i 能被 j 整除 { 是否为素数 假 break // 跳出内层循环不是素数 } } if 是否为素数 真 { 输出(i) } }这段伪代码的任何一行都不涉及某一门语言的语法细节但任何会写程序的人都能看懂也都能翻译成自己熟悉的语言。7.2 验证伪代码的正确性手动干跑和边界检查伪代码写完不能拍胸脯说“肯定没问题”尤其是给别人用的伪代码我通常用“手动干跑”的方式过一遍。所谓干跑就是拿几个典型输入值把伪代码的每一条分支走一遍核对变量变化和输出。就拿100这个起始值来说i100内层j从2跑到99中间能被2整除所以100直接标记非素数不输出。再看101j2时101%2不等于0j3时也不等于0一路跑到100都没整除于是101被输出。再检查边界200200%2等于0非素数不输出。跑完三个值基本能确定逻辑主干没问题。接下来是边界检查如果i等于100内层循环需要判断j从2到99循环能正常进入i如果等于200也一样。如果把题目改成求2到3之间的素数内层循环就要注意会不会出现j从2到1的脏数据虽然这里用不到但写伪代码的人心里要有这个意识。这种验证习惯对模式切换伪代码同样重要。在写模式切换伪代码的时候状态表里每一格你都要问一次如果当前状态是X来了事件Y会发生什么干跑一遍所有表格组合很多漏洞都能在写代码前暴露出来。8. 伪代码的六条军规靠这些躲开九十年代就存在的老坑最后把这几年做方案、写文档、审别人伪代码的经验总结成几条硬规则你可以把这一部分当作一个速查清单。8.1 命名有“代码样”但别用具体API伪代码里的变量、模式、事件命名要和真实代码接近使用有语义的英文单词或拼音缩写比如current_mode、evt_button、AP_FAT_MODE。避免用a、b、c这种无意义命名。但又不要直接写死某个具体API调用比如写“write_reg(0x1234, 0x56)”这就是真代码不是伪代码。伪代码应该停留在“调用某个动作函数”层级比如“写寄存器使能配置模式”具体地址留给实现阶段。8.2 分支条件必须写完整不能只写一半很多人写伪代码喜欢写if 模式 运行模式 { 执行运行逻辑 }然后就没有else分支了。这倒也可以但在模式切换这种场景下我建议把非法的、不能处理的分支也写出来if 模式 运行模式 { 执行运行逻辑 } else { 报错并拒绝 }原因很简单模式切换的bug多半出现在“你不希望发生的分支”里把它显式写出来会让问题提前暴露。8.3 每个“下一模式”要出现在状态表能查到的地方状态表驱动型伪代码里如果某一行说“切换到配置模式”那么配置模式必须和当前的源模式构成一个合法转换。否则即使伪代码写得工整翻译成代码后也会出现一个“不可能到达的状态”运行一段时间后炸出诡异bug。8.4 注释写“为什么”不写“做了什么”伪代码本身的逻辑已经清楚表达了“做了什么”所以注释别写成“设置当前模式为配置模式”这种注释是废话。注释应该写“为什么要切到这个模式”“如果这里失败会有什么影响”。你过三个月回来看伪代码看到的应该是决策依据而不是一份流水账。8.5 保持伪代码在“人类语言”和“编程语言”之间的平衡伪代码太偏向人类语言会含糊不清太偏向编程语言又失去了伪代码的意义。我的判断标准是一个不懂你业务的人拿到这份伪代码能不能猜到大概流程如果能这份伪代码的抽象层级就对了。模式切换伪代码尤其需要这个平衡因为模式切换本身是业务逻辑不是纯粹的计算逻辑读者的背景可能千差万别。8.6 配一个“模式转换总览”段落如果伪代码所在的文档是设计文档我建议在伪代码前面加一个模式总览列出所有模式名、所有事件名、合法转换表。这相当于给读文档的人一张地图伪代码只是地图上的一条条路径。这是我这些年写方案总结出来的习惯每次加了这张表评审会上关于模式切换的争论都会少很多。一点收尾的实在话干这行时间长了你会发现伪代码被很多人当成一种可有可无的过渡产物——需求着急就直接写代码伪代码反而是浪费时间。但就模式切换这类场景来说我始终认为伪代码是性价比最高的设计工具它花不了十分钟却能把最容易被忽略的状态边界、非法组合、切换动作一次性暴露出来。我在实际项目里吃过“状态转换没提前梳理”的亏也吃过“伪代码写得太烂完全无法指导编码”的亏后来慢慢形成这套写法再处理模式切换需求时明显顺了很多。如果你现在正被某个“模式切换”问题困扰我的建议是先别打开编译器先打开一个空白文档把模式、事件、状态转换表列出来再按这篇文章里的思路写一份伪代码。等你写完这份伪代码大概率会发现之前想不清晰的细节已经自己浮出水面了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑