画状态图分 4 步:列全订单会经历的状态,用箭头连出转换并写上触发事件,按条件分去向时加守卫条件,最后画出起点和终态。下文用一个虚构的电商订单,把整套流转画成一张图。
核心观点:状态图只盯一个对象:圆角框是状态,箭头是转换,箭头上写「事件 [守卫条件]」;每个状态都要有出路,结束处画上终态。
状态图的5个基本元素
状态图由状态、转换、事件、守卫条件、起点和终态 5 种元素组成,画法出自 UML 状态机图。
| 元素 | 画法 | 订单里的例子 |
|---|---|---|
| 状态 | 圆角矩形 | 待支付、待发货 |
| 转换 | 带箭头的线 | 待支付 → 待发货 |
| 事件 | 箭头上的文字 | 商家发货 |
| 守卫条件 | 事件后的方括号 | [金额一致] |
| 起点、终态 | 实心圆;圆圈套实心圆 | 提交订单进入待支付 |
UML 2.5.1 规范里,转换文字写作「事件 [守卫条件] / 动作」,如「支付回调 [金额一致] / 通知商家」,用不到的可省略。
第1步:列全订单状态
状态是订单停留的一种情况,用「待…」「已…」「…中」命名,正常和异常流程都要列。
- 正常流程:待支付、待发货、待收货、已完成。
- 异常流程:已取消、退款中、已退款。
- 别混进动作:「支付」「发货」是事件,不是状态;状态说的是订单现在怎样。
第2步:连转换,写事件
每条箭头写一个触发事件,如「商家发货」;先填转换表再画图,方便和研发、测试逐行核对。
| 当前状态 | 事件 [守卫条件] | 下一状态 |
|---|---|---|
| 待支付 | 支付回调 [金额一致] | 待发货 |
| 待支付 | 支付回调 [金额不一致] | 待支付(人工核对) |
| 待支付 | 用户取消或超时未支付 | 已取消 |
| 待发货 | 商家发货 | 待收货 |
| 待发货 | 申请退款 | 退款中 |
| 退款中 | 退款到账 | 已退款 |
| 待收货 | 确认收货或超时自动确认 | 已完成 |
第3步:加守卫条件
同一个事件要按条件走不同的路时,在事件后面用方括号写守卫条件,条件成立才转换。
- 示例:支付回调后,金额与订单一致进入待发货,不一致留在待支付等人工核对。
- 分支多时画菱形选择节点,每条出线写一个条件;UML 规范建议留一条 [else],免得无路可走。
第4步:画起点和终态
从实心圆画箭头到待支付,写上「提交订单」;已完成、已取消、已退款之后不再变化,各画一条箭头到终态。
Mermaid写状态图:订单示例
Mermaid 的 stateDiagram-v2 一行写一条转换,冒号后面是箭头上的文字,状态名可直接写中文。
[*]在箭头左边是起点,在右边是终态;选择节点用<<choice>>声明。- 官方文档没有单独的守卫语法,方括号直接写进冒号后的文字。
下面的代码按官方文档写法,我们在本机用 Mermaid 11.17.2 渲染通过
状态图常见的4个错误
- 把动作画成状态:框里写「支付」「发货」,分不清状态和事件。
- 箭头上不写事件:看不出什么时候会变,开发和测试只能猜。
- 漏掉异常流程:只画下单到完成一条线,取消、退款都没画。
- 进得去出不来:「退款中」只有进来的箭头、没有出去的,订单会一直卡住。
总结
画状态图先列全状态,再连转换、写事件,按条件分去向时加守卫,最后画起点和终态。画完顺着箭头走一遍,每个状态都有出路,规则就讲清了。
互动问题:你们系统里哪个对象状态多、规则乱?评论区写出它的状态,我们挑几条帮你看漏了哪条转换。