🎯 概述
本指南将带您逐步了解电话呼叫控制系统的电话呼叫控制系统的UML 状态机图。它专注于外呼呼叫生命周期,说明电话线路如何根据用户操作和网络事件在不同状态之间转换。
该图涵盖了正常路径(呼叫建立成功)以及异常路径(错误、超时、线路忙),强调鲁棒性、异常处理和清晰的状态转换——这些是实时通信系统的关键原则。
🧩 UML 状态机的核心概念
在深入查看图表之前,请先了解以下 UML 基础概念:
| 概念 | 描述 |
|---|---|
| 状态 | 对象满足特定条件或执行操作的阶段。 |
| 转换 | 由事件触发从一个状态到另一个状态的改变。 |
| 事件 | 导致状态转换的发生(例如,挂断, 有效号码). |
| 自转换 | 起始和结束于同一状态的转换(例如,digit(n) 在…期间拨号). |
| 伪状态 | 特殊控制点,例如初始 或 终止 这些并非实际状态。 |
| 组合状态 | 包含子状态的状态(例如错误 状态,其中包含忙音, 快速忙音, 录音消息). |
| 守卫条件 | 一个布尔表达式,只有当其值为真时,转换才会发生。 |
✅ 专业提示: 使用
事件 [守卫] / 动作语法在 UML 中用于记录触发器、条件和副作用。
🔄 外呼生命周期:逐步分解
1. 发起与拨号阶段
🔹 初始伪状态 → 空闲
- 系统启动于初始伪状态.
- 尚无活动;电话处于挂机状态。
🔹 空闲 → 拨号音(onHook)
- 事件:
onHook(用户拿起听筒) - 转换:
onHook → 拨号音 - 操作:生成拨号音;准备接收数字输入。
📌 这是呼叫生命周期中首次可见的状态变更。
🔹 拨号音 → 拨号中(digit(n))
- 事件:
digit(n)(用户输入一个数字) - 转换:
digit(n) → 拨号中 - 状态:进入
拨号中模式。
🔹 自转换:拨号中 → 拨号中(digit(n))
- 事件:
digit(n)(输入多个数字) - 守卫条件: 无(始终允许)
- 操作: 将数字追加到正在拨打的号码中。
- 目的: 允许在不离开
拨号状态的情况下连续输入数字。
💡 自转换对于处理电话号码等输入序列至关重要。
2. 连接逻辑与异常处理
🔹 拨号 → 连接(validNumber)
- 事件:
validNumber(号码已完整验证) - 转换:
validNumber → 连接 - 操作: 与网络发起呼叫建立。
🔹 拨号 → 录制消息(invalidNumber)
- 事件:
invalidNumber(例如:长度错误、前缀无效) - 转换:
invalidNumber → 录制消息 - 操作: 播放预录消息:“您拨打的号码无法使用。”
🔹 连接 → 忙音(numberBusy)
- 事件:
号码忙 - 转换:
numberBusy → 忙音 - 操作:播放忙音;告知用户线路正忙。
🔹 连接中 → 快速忙音(中继忙)
- 事件:
中继忙 - 转换:
trunkBusy → 快速忙音 - 操作:播放快速忙音;指示网络拥塞。
⚠️ 注意:这些是错误状态会中断正常流程。必须妥善处理。
3. 超时与警告机制
🔹 拨号中 → 警告(超时)
- 事件:
超时在30秒无活动后 - 转换:
timeout → 警告 - 操作:播放警告提示音;通知用户继续或挂断。
🔹 警告 → 超时(超时)
- 事件:
超时10 秒后再次 - 转换:
timeout → Timeout - 操作:取消呼叫尝试;返回到
空闲.
⏱️ 超时逻辑可防止无限等待并提升用户体验。
4. 活跃通话与断开连接
🔹 连接中 → 振铃(已路由)
- 事件:
已路由(网络成功路由该呼叫) - 转换:
已路由 → 振铃 - 操作:向被叫方发送振铃信号。
🔹 振铃 → 已接通(被叫方接听)
- 事件:
被叫方接听 - 转换:
被叫方接听 → 已接通 - 操作:建立音频连接;开始通话录音(如果已启用)。
🔹 已接通 → 已断开(挂机 或 被叫方挂断)
- 两种断开连接的路径:
- 用户挂断:
onHook → 已断开 - 对方挂断:
calledPhoneHangsUp → 已断开
- 用户挂断:
🔄 两种转换均指向
已断开到达最终状态.
🔹 已断开 → 最终状态
- 事件: 无(隐式或通过清理操作)
- 转换:
已断开 → 最终 - 操作: 清理资源,记录通话时长,更新统计信息。
✅ 最终状态表示通话生命周期的结束。
🎨 清晰度的视觉设计原则
为了使复杂的状态机可读且易于维护:
| 原则 | 实现 |
|---|---|
| 核心成功路径 | 将主流程(空闲 → 拨号音 → 拨号中 → 连接中 → 振铃 → 已连接)保持为一条清晰的垂直或水平线。 |
| 异常向外分支 | 将错误状态(忙音、快速忙音、录音消息)作为侧向分支放置。 |
| 分组相关状态 | 使用复合状态 来表示错误条件(见下文)。 |
| 明智地使用伪状态 | 初始 和 最终 应明确标记。 |
| 避免交叉转换 | 避免箭头重叠;如有需要,请使用正交区域。 |
🔧 高级建模技术
✅ 复合状态:“错误”分组
不要列出 忙音, 快速忙音、和 录音消息 作为独立状态,将它们归入一个 复合状态,名为 错误:
[错误]
├── 忙音
├── 快速忙音
└── 录音消息
- 入口动作: 播放错误音或消息。
- 出口动作: 返回至
拨号音或空闲在用户响应后。
✅ 优势:减少视觉杂乱并提高可扩展性。
✅ 守卫条件(可选增强)
添加守卫以细化转换:
digit(n) [number.length < 15] → 拨号
validNumber [number.isInternational] → 连接中
🛠️ 守卫可防止无效转换并支持条件逻辑。
📌 关键要点:复杂状态机的最佳实践
| 实践 | 为何重要 |
|---|---|
| 建模异常路径 | 真实系统会失败。设计时应考虑无效号码, 超时, 中继忙确保可靠性。 |
| 使用动作表达式 | 包含/ logCallAttempt()或/ playTone()以显示副作用。 |
| 保持事件描述详尽且面向动作 | 使用onHook, routed, calledPhoneAnswers 而不是 e1, e2. |
| 清晰命名状态 | 避免 状态1, 状态2。使用 拨号中, 振铃中, 已连接. |
| 记录假设条件 | 例如,“30 秒无活动后超时”应在注释中注明。 |
💻 代码生成:PlantUML 与 Mermaid
以下是 即插即用的代码块 以您首选的格式生成此图表。
✅ PlantUML 代码
@startuml
[*] --> Idle
Idle --> DialTone : onHook
DialTone --> Dialing : digit(n)
Dialing --> Dialing : digit(n) ' 自转换
Dialing --> Connecting : validNumber
Dialing --> RecordedMessage : invalidNumber
Dialing --> Warning : timeout
Warning --> Timeout : timeout
Connecting --> Ringing : routed
Connecting --> BusyTone : numberBusy
Connecting --> FastBusyTone : trunkBusy
Ringing --> Connected : calledPhoneAnswers
Connected --> Disconnected : onHook
Connected --> Disconnected : calledPhoneHangsUp
Disconnected --> [*] : cleanup
state "Error" as ErrorState {
state "BusyTone" as BusyTone
state "FastBusyTone" as FastBusyTone
state "RecordedMessage" as RecordedMessage
}
' 内部动作
Idle : entry / 等待摘机
DialTone : entry / 播放拨号音
Dialing : entry / 收集数字
Connecting : entry / 路由呼叫
Ringing : entry / 振铃远程电话
Connected : entry / 建立呼叫会话
Disconnected : entry / 终止会话
@enduml 📥 使用方法:粘贴到PlantUML 在线版或您的 IDE 插件。
✅ Mermaid 代码

stateDiagram-v2
[*] --> Idle
Idle --> DialTone : onHook
DialTone --> Dialing : digit(n)
Dialing --> Dialing : digit(n) ' 自转换
Dialing --> Connecting : validNumber
Dialing --> RecordedMessage : invalidNumber
Dialing --> Warning : timeout
Warning --> Timeout : timeout
Connecting --> Ringing : routed
Connecting --> BusyTone : numberBusy
Connecting --> FastBusyTone : trunkBusy
Ringing --> Connected : calledPhoneAnswers
Connected --> Disconnected : onHook
Connected --> Disconnected : calledPhoneHangsUp
Disconnected --> [*] : cleanup
state Error {
BusyTone
FastBusyTone
RecordedMessage
}
Connecting --> BusyTone : numberBusy
Connecting --> FastBusyTone : trunkBusy
Dialing --> RecordedMessage : invalidNumber
note right of BusyTone
播放标准忙音
end note
note right of FastBusyTone
播放快速忙音(网络拥塞)
end note
note right of RecordedMessage
播放录音消息:"号码不可用。"
end note
note right of Timeout
40 秒后取消呼叫尝试
end note 📥 使用方法:粘贴到Mermaid 在线编辑器或支持的 Markdown 工具(VS Code、Obsidian 等)。
📚 总结与最终思考
此电话呼叫控制系统状态机是一个真实世界示例展示了 UML 如何以高可靠性对复杂的事件驱动系统进行建模。
✅ 此图表有效的关键:
- 清晰的正常流程且具有逻辑流。
- 全面的错误处理.
- 使用自转换, 复合状态,和守卫条件.
- 通过分组 和 注释.
🛠️ 何时使用此模式:
- 电话系统
- 物联网设备控制
- 用户会话管理
- 工作流引擎
- 具有有限状态逻辑的嵌入式系统
📝 想要扩展此功能?
考虑添加:
- 通话录音 状态(包含
startRecording,stopRecording事件) - 呼叫转移 逻辑(条件路由)
- 呼叫等待 支持(并行状态)
- 呼叫转接 作为
已连接 - 状态历史(浅层/深层历史)用于中断后重新进入
📌 最终建议
始终同时建模成功路径和失败路径。
仅处理“理想路径”的状态机是不完整的,且在生产环境中容易引发错误。
将此指南作为模板用于建模任何实时系统,其中状态转换, 事件,以及错误弹性至关重要。
✅ 准备好生成、可视化或扩展了吗?
👉 复制PlantUML或Mermaid代码,并将其集成到您的文档、架构图或系统设计文档中。
如果您需要PDF 版本, 交互式图表,或集成到更大的系统模型中(例如,包含组件图或序列图)!
📘 “最好的系统不仅正确无误,还能预见故障。”
— 使用UML状态机进行设计












