PlantUML 状态图实战:订单状态机的 4 种写法
状态图是 PlantUML 里被低估的一类图:能精确描绘复杂对象(订单、登录会话、提交流程)的所有可能状态、转换条件和进入动作。
状态图能解决什么问题
业务里的订单生命周期经常这样:
- 待付款 → 已付款 → 发货中 → 已签收 → 已完成
- 已付款 → 申请退款 → 已退款
- 待付款 → 取消
- 已签收 → 申请售后 → 售后处理中 → 售后完成
代码实现时这些都是 if/else/switch 的海洋。状态图先把业务对象的生命周期画清楚,代码照着搬实现就行。
1. 最基本的状态图
1 | @startuml |
要点:
[*]表示起点和终点状态A --> 状态B : 触发事件是从 A 到 B 的转换,标签是触发事件- 渲染出来圆角矩形 + 黑色箭头 + 灰底
这种基本图覆盖了 80% 的业务对象状态。
2. 加守卫条件
不是所有转换都能发生。在 --> : 后面可以接 [] 标记守卫:
1 | @startuml |
[条件] 是 UML 标准的守卫语法。PlantUML 把多个守卫放一行写也可:
1 | 待付款 --> 已取消 : 用户取消 [库存未扣减] |
3. 加进入动作和活动
进入某个状态时要做什么(比如发邮件、扣库存):
1 | @startuml |
语法:源状态 --> 目标状态 : 触发事件 / 进入目标时执行
注意斜杠前后空格。动作可以是「给用户发短信」「调库存接口」之类的业务动作描述,不需要真正写代码。
4. 复合状态 / 子状态
「发货」是个流程,不只是一个动作。你需要嵌套 state:
1 | @startuml |
state X { ... } 表示 X 这个状态内部还有子状态。PlantUML 会画成大圆角框里嵌小圆角框。
5. 历史标记(H)和深历史(H*)
子状态机返回时是回到入口,还是回到「上次停留的状态」?
1 | @startuml |
不过 PlantUML 对 H / H* 支持有限,复杂回退要靠自己实现:退出子状态时记录当前状态、再次进入时查记录恢复到原状态。
6. 并发区域(fork / join)
同一状态下多件事并行:
1 | @startuml |
--> 默认箭头本身就能表达顺序,要画并发用 fork / join 这两个关键字:
1 | state fork点 <<fork>> |
但 PlantUML 里更简单的方式是用同一个状态进入两条转换:
1 | 待支付 --> 风控审核 : 并行 -1 |
不标 fork/join 也能让评审理解。
7. 时间触发的状态机
PlantUML 状态图对时间触发支持有限(不像 UML 标准里能写 after 24h)。常见折中:
1 | @startuml |
<&hourglass> 这种图标表示「由外部定时器触发」。
实践中代码端:
1 | // 状态图描述的是「应该发生什么」 |
实战例子:登录会话
1 | @startuml |
这套状态图让代码一眼看懂:
1 | // 状态机驱动实现 |
评审 checklist
- 所有状态都用
[*]起点和终点表示吗? - 转换条件(
条件方括号)写在:后面? - 业务动作(
/ 动作)放在哪里,需要被实现吗? - 复合状态的子状态图能独立读懂吗?
- 时间触发的转换有明确 cron / 定时器文档吗?
- 状态图能覆盖所有合法路径和异常路径吗?
实战组合
把状态图配合活动图一起用:
1 | @startuml |
踩坑清单
--> :后面的标签不能太长:待付款 --> 已超时 : 用户点击取消且支付网关回调失败且订单未确认—— 这种长描述截断,建议note拆开写。[*]不能作转换的源:要从[*]进入必须显式写[*] --> X : event。- 复合状态里再写
[*] -->:嵌套子状态机的入口是父状态的入口,不要到处都[*] -->。 - 守卫条件不写
[]:PlantUML 没方括号就把条件当成转换标签了,整体错乱。 - 时间触发不灵:
after 24h之类 PlantUML 不识别,要么用图标表示定时任务触发,要么转移到代码端定时任务里。
对比 UML 标准
PlantUML 状态图支持 UML State Machine 大部分核心功能:
| 特性 | UML 标准 | PlantUML |
|---|---|---|
| 简单状态 | ✅ | ✅ |
| 起始 / 终止 | ✅ | ✅ |
| 转换(trigger) | ✅ | ✅ |
| 守卫(guard) | ✅ | ✅ |
| 进入 / 退出动作 | ✅ | ✅ (entry / exit) |
| 复合状态 | ✅ | ✅ |
| 历史(H / H*) | ✅ | ⚠️ 部分支持 |
| 深历史 | ✅ | ⚠️ 部分支持 |
| 同步(fork / join) | ✅ | ✅ |
时间触发 after |
✅ | ❌(用图标或外部定时器) |
PlantUML 写的状态图能直接给 UML 工具(EA、StarUML)解析。
一句话总结
状态图是 PlantUML 里被严重低估的一类图。在写代码前用状态图先过一遍业务流程,状态机的逻辑就自然落地到了代码里 —— 不再写一堆散乱的 if/else。
- 标题: PlantUML 状态图实战:订单状态机的 4 种写法
- 作者: puml.online
- 创建于 : 2026-07-29 15:00:00
- 更新于 : 2026-08-14 21:34:29
- 链接: https://puml.online/blog/plantuml-state-diagram/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。