完整指南:使用 UML 狀態機建模電話呼叫控制系統

🎯 概覽

本指南將引導您完成電話呼叫控制系統的設計與建模,使用UML 狀態機圖。本指南著重於外撥呼叫的生命週期,說明電話線如何根據使用者操作與網路事件在不同狀態之間轉換。

該圖表涵蓋了正常路徑(呼叫設定成功)與異常路徑(錯誤、超時、佔線),強調魯棒性、例外處理與清晰的狀態轉換——這些是即時通訊系統的核心原則。


🧩 UML 狀態機的核心概念

在深入圖表之前,請先理解這些 UML 基礎概念:

概念 說明
狀態 物件滿足特定條件或執行特定動作的狀態。
轉換 由事件觸發的從一個狀態到另一個狀態的變化。
事件 導致轉換的發生(例如:掛機有效號碼).
自我轉換 起始與終止於同一狀態的轉換(例如:digit(n) 在…期間 撥號).
偽狀態 特殊控制點,例如 初始終止 並非實際狀態。
複合狀態 包含子狀態的狀態(例如 錯誤 狀態,其中包含 忙音快速忙音錄製訊息).
保護條件 一個布林表達式,必須為真才能發生轉換。

✅ 專業提示: 使用 event [guard] / action 語法在 UML 中記錄觸發器、條件和副作用。


🔄 外撥通話生命週期:逐步分解

1. 啟動與撥號階段

🔹 初始偽狀態 → 閒置

  • 系統起始於初始偽狀態.
  • 尚未有任何活動;電話處於掛機狀態。

🔹 閒置 → 撥號音 (onHook)

  • 事件: onHook(用戶拿起聽筒)
  • 轉換: onHook → DialTone
  • 動作:產生撥號音;準備輸入數字。

📌 這是通話生命週期中第一個可見的狀態變更。

🔹 撥號音 → 撥號中 (digit(n))

  • 事件: digit(n)(用戶輸入一個數字)
  • 轉換: digit(n) → Dialing
  • 狀態:進入撥號中模式。

🔹 自我轉換:撥號中 → 撥號中 (digit(n))

  • 事件: digit(n)(輸入多個數字)
  • 守衛: 無(始終允許)
  • 動作: 將數字追加至正在撥打的號碼。
  • 目的: 允許在不離開「撥號」」狀態下持續輸入數字。

💡 自我轉換對於處理如電話號碼等輸入序列至關重要。


2. 連線邏輯與例外處理

🔹 撥號 → 連線(validNumber)

  • 事件: validNumber(號碼已完整驗證)
  • 轉換: validNumber → 連線
  • 動作: 與網路啟動通話設定。

🔹 撥號 → 播放預錄訊息(invalidNumber)

  • 事件: invalidNumber(例如:長度錯誤、前綴無效)
  • 轉換: invalidNumber → 播放預錄訊息
  • 動作: 播放預錄訊息:「您撥打的號碼無法使用。」

🔹 連線 → 忙音(numberBusy)

  • 事件: 號碼忙線
  • 轉換: numberBusy → 忙音
  • 動作:播放忙音;通知用戶該線路已被佔用。

🔹 連接中 → 快速忙音 (中繼線忙)

  • 事件: 中繼線忙
  • 轉換: trunkBusy → 快速忙音
  • 動作:播放快速忙音;表示網路擁塞。

⚠️ 注意:這些是錯誤狀態會中斷正常流程。必須以妥善方式處理。


3. 超時與警告機制

🔹 撥號中 → 警告 (超時)

  • 事件: 超時在 30 秒無活動後
  • 轉換: timeout → 警告
  • 動作:播放警告嗶聲;通知用戶繼續操作或掛斷。

🔹 警告 → 超時 (超時)

  • 事件: 超時10 秒後再次
  • 轉換: 超時 → 超時
  • 動作:取消呼叫嘗試;返回至閒置.

⏱️ 超時邏輯可防止無限等待並提升使用者體驗。


4. 通話中與斷線

🔹 連接中 → 振鈴(已路由)

  • 事件: 已路由(網路成功路由該通話)
  • 轉換: 已路由 → 振鈴
  • 動作:向被叫方發送振鈴訊號。

🔹 振鈴 → 已連線(被叫方接聽)

  • 事件: 被叫方接聽
  • 轉換: 被叫方接聽 → 已連線
  • 動作:建立音訊連線;開始通話錄音(若已啟用)。

🔹 已連線 → 已斷線(掛上聽筒 或 被叫方掛斷)

  • 兩種斷線途徑:
    1. 使用者掛斷: 掛上聽筒 → 已斷線
    2. 對方掛斷: calledPhoneHangsUp → 已斷開

🔄 兩種轉換均指向已斷開 之後才到達最終狀態.

🔹 已斷開 → 最終狀態

  • 事件: 無(隱含或透過清理動作)
  • 轉換: 已斷開 → 最終
  • 動作: 清理資源、記錄通話時長、更新統計數據。

✅ 最終狀態代表通話生命週期的結束。


🎨 用於清晰度的視覺設計原則

為了讓複雜的狀態機易於閱讀與維護:

原則 實作
主要成功路徑置於中央 將主要流程(閒置 → 撥號音 → 撥號中 → 連接中 → 振鈴 → 已接通)保持為一條清晰的垂直或水平線。
例外情況向外分支 將錯誤狀態(忙音、快速忙音、錄製訊息)作為側邊分支放置。
將相關狀態分組 使用複合狀態 來處理錯誤條件(見下文)。
謹慎使用偽狀態 初始 和 最終 應清楚標示。
避免交叉轉換 避免箭頭重疊;如有需要,請使用正交區域。

🔧 進階建模技術

✅ 複合狀態:「錯誤」分組

與其列出 忙音快速忙音、以及 錄製訊息 作為獨立狀態,請將它們歸類至一個 複合狀態 名為 錯誤:

[錯誤] 
├── 忙音
├── 快速忙音
└── 錄製訊息
  • 進入動作: 播放錯誤音效或訊息。
  • 退出動作: 返回至 撥號音 或 閒置 於使用者回應後。

✅ 效益:減少視覺雜訊並提升可擴展性。


✅ 保護條件(可選增強)

新增保護條件以精細化狀態轉換:

digit(n) [number.length < 15] → 撥號中
validNumber [number.isInternational] → 連線中

🛠️ 保護條件可防止無效的狀態轉換並支援條件邏輯。


📌 重點摘要:複雜狀態機的最佳實踐

實作 為何重要
模擬不順暢路徑 真實系統會失敗。設計時應考慮 無效號碼逾時線路繁忙可確保可靠性。
使用動作表達式 包含 / logCallAttempt()或 / playTone()以顯示副作用。
保持事件描述詳盡且以動作為導向 使用 onHookroutedcalledPhoneAnswers 而非 e1e2.
明確命名狀態 避免 State1State2。使用 撥號中振鈴中已連線.
記錄假設條件 例如,「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 如何以高可靠性建模複雜且事件驅動的系统。

✅ 此圖表有效的關鍵:

  • 清晰的 成功路徑 且邏輯流暢。
  • 全面的 錯誤處理.
  • 運用 自我轉換複合狀態,以及 守衛條件.
  • 透過 分組 以及 註解.

🛠️ 何時使用此模式:

  • 電話系統
  • 物聯網裝置控制
  • 使用者會話管理
  • 工作流程引擎
  • 具有有限狀態邏輯的嵌入式系統

📝 想要擴充此功能嗎?

考慮新增:

  • 通話錄音 狀態(包含 startRecordingstopRecording 事件)
  • 通話轉接 邏輯(條件式路由)
  • 來電等待 支援(平行狀態)
  • 通話轉移 作為 已連線
  • 狀態歷史(淺層/深層歷史)用於中斷後重新進入

📌 最終建議

務必同時建模成功路徑與失敗路徑。
僅處理「順利路徑」的狀態機是不完整的,且在生產環境中容易出現錯誤。

將本指南作為範本來建模任何實時系統,其中狀態轉換事件,以及錯誤韌性至關重要。


✅ 準備好生成、可視化或擴充了嗎?
👉 複製以下PlantUMLMermaid程式碼,並將其整合至您的文件、架構圖或系統設計文件中。

如果您需要PDF 版本互動式圖表,或整合至更大的系統模型(例如,包含元件或序列圖)!


📘 「最佳系統不僅正確無誤,更能預見失敗。」
— 使用 UML 狀態機進行設計