完整逐步教程:如何創建狀態機圖(適用於完全初學者)

UML 狀態圖 是一種強大的視覺化工具,透過展示系統如何根據事件在不同狀態之間轉換,來模擬系統的動態行為。它記錄了物件或流程的生命周期——顯示其可能的狀態 處於 中,什麼觸發了變更,以及狀態變更期間發生的動作——使其成為理解複雜系統(如交通信號燈、自動販賣機、登入流程或遊戲角色)的理想工具。透過專注於狀態(例如「紅色」、「等待付款」或「跳躍」)、轉換(由事件驅動,如「計時器到期」或「按鈕按下」)以及條件(守衛),狀態圖提供了清晰性,避免邏輯漏洞,並成為設計與程式碼的基礎。無論你是初學者學習系統建模,還是開發者打造穩健的軟體,掌握狀態圖將使你具備以精確與清晰的方式思考、設計和溝通系統行為的能力。

State Machines for Everyone — Part 1 Introduction | by Alex Dodge | Well  Red | Medium

💡 目標:學習如何使用狀態機來模擬現實世界中的系統——從構想到清晰且專業的圖示。

🔑 你必須首先理解的關鍵概念

概念 它的含義 為何重要
狀態 系統所處的條件或情境(例如 紅色等待投入硬幣) 顯示任何時刻正在發生的事
事件 觸發變化的某種事物(例如 投入硬幣計時器到期) 導致狀態之間的移動
轉換 從一個狀態指向另一個狀態的箭頭 透過事件連結狀態
初始狀態 起始點 (●) 總會有一個
終止狀態 流程結束 (○) 可選 — 不一定需要
守衛 [條件] 轉移發生時必須為真的條件 增加邏輯(例如:金額足夠嗎?)
動作 / 進入/執行 進入、進行中或離開狀態時會發生什麼 為狀態增加行為

📌 試著思考:
「這個系統可以處於 X 種狀態。
當 Y 發生時,它會轉移到 Z.”
這就是一個狀態機!


🛠 步驟 0 – 思維模式:提出這些問題

在繪製任何內容之前:

  • 這個事物可能處於哪些 明顯不同的狀態 這個事物可能處於的狀態?

  • 什麼 事件(使用者操作、時間、錯誤)會導致變更嗎?

  • 它能同時處於兩個狀態嗎?(不行 → 基本的狀態機是互斥的。)

👉 範例:一個燈的開關不是開啟就是關閉絕不會同時兩者皆是。


🧩 步驟 1 – 選擇一個具體的事物來建模

✅ 適合初學者的選擇:

  • 閘門(鎖定/解鎖)

  • 交通號誌(紅/綠/黃)

  • 自動販賣機

  • 登入系統

  • 訂單狀態:已建立 → 已付款 → 已出貨 → 已送達

❌ 避免:

  • 「整個線上商店」→ 過於龐大

  • 「使用者體驗」→ 過於模糊

✏️ 從簡單開始。先掌握小範例。


📌 步驟 2 – 列出狀態(使用名詞或現在分詞)

寫下4到8個實際的狀態.

使用形容詞或現在分詞來讓它看起來像是一種狀態:

  • 紅色

  • 綠色

  • 黃色

  • 等待硬幣

  • 發放物品

  • 準備中

  • 付款失敗

✅ 提示:如果你有超過 10 個狀態 → 將系統拆分成較小的部分。


🖌 步驟 3 – 將狀態繪製為圓角矩形

使用圓角矩形:

[ 紅色 ]
[ 綠色 ]
[ 等待硬幣 ]

✅ 工具:

  • draw.io / diagrams.net(最佳免費選擇)

  • Excalidraw(手繪風格)

  • PlantUML(基於文字 → 易於版本控制)

  • Lucidchart / Miro


🔷 步驟 4 – 添加初始狀態(黑色圓點)

繪製一個填滿的黑色圓形並以箭頭指向第一個狀態。

[*] --> 紅色

這個[*]代表「初始狀態」——這是起始點。


➡️ 步驟 5 – 使用事件繪製轉移

針對每個狀態,請問:

「在此處會發生什麼事情,讓我離開這個狀態?」

以以下內容標示箭頭:

事件 [守衛] / 動作

🔹 從簡單開始:僅需事件事件 / 動作

常見事件:

  • 投入硬幣

  • 計時器到期

  • 付款失敗

  • 按鈕被按下

  • 行人按鈕

  • 逾時


✅ 步驟 6 – 添加最終狀態(可選)

使用一個粗邊圓形作為最終狀態。

[已交付] --> [●]

並非所有系統都有最終狀態(例如永遠運行的交通信號燈)。


🔁 步驟 7 – 添加現實中的邊界情況

詢問:

  • 可以取消嗎?→新增取消→ 回到空閒

  • 時間會結束嗎?→逾時→ 回到等待

  • 會失敗嗎?→新增錯誤 → 返回開始

  • 它能保持在同一狀態嗎?→自轉移

範例:自轉移(增加更多金額):

[有信用] -- 投入硬幣 --> [有信用]

🚦 步驟 8 – 使用守衛進行智慧邏輯

相同的事件導致不同的結果,使用守衛.

範例:

如果你按下pedButton期間綠色,但目前還沒有需求 → 你進入綠色且行人等待.

但如果需求已經設定 → 你只需忽略它。

[車輛綠燈] --> [車輛綠燈] : pedButton / 設定需求 = true

這是一個帶有動作的自轉移—— 不是新的狀態。


🎯 步驟 9 – 添加進入/執行/退出動作(可選但強大)

您可以在狀態框內撰寫動作狀態框內:

[紅色]
進入 / 開啟紅燈
退出 / 關閉紅燈
執行 / 等待 30 秒

有助於釐清行為,而不會使轉移變得混亂。


✅ 步驟 10 – 最終檢查清單(自我提問)

✅ 檢查 為何重要
只有一個初始狀態嗎? 必須從某處開始
所有狀態都有外出箭頭(最終狀態除外)? 沒有死路
沒有無法到達的狀態嗎? 每個狀態都應該可以到達
轉移是否以事件標記? 明確的因果關係
箭頭不表示「前往 X」——箭頭僅顯示方向 更乾淨
是否包含取消 / 超時 / 錯誤路徑? 真實系統會失敗——請做好準備
圖表是否能完整顯示在螢幕上? 清晰且易讀

📋 快速參考:PlantUML 語法(UML 標準)

符號 含義
[*] 初始狀態
[*] --> 狀態 從此狀態開始
狀態 --> 狀態 轉移
事件 [保護條件] / 動作 箭頭上的標籤
狀態 "名稱" 命名狀態(可選)
狀態 "X" 為 X 複雜名稱的別名
狀態右側的註解 註解框

🎯 範例 1:簡單的交通號誌(三狀態循環)

非常適合完全的新手。

🧠 實際應用:

  • 基本交通號誌循環:紅色 → 綠色 → 黃色 → 紅色

✅ 狀態:

  • 紅色

  • 綠色

  • 黃色

🔄 事件:

  • 計時器到期(30 秒後、25 秒後、5 秒後)

🛠 PlantUML 程式碼(可複製貼上):

@startuml
skinparam monochrome true
[*] --> 紅色
紅色 --> 綠色 : after(30s)n計時器到期
綠色 --> 黃色 : after(25s)n計時器到期
黃色 --> 紅色   : after(5s)n計時器到期

紅色   : entry / 開啟紅燈
綠色 : entry / 開啟綠燈
黃色: entry / 開啟黃燈

note right of 紅色
  車輛必須停下
end note

note right of 綠色
  車輛可以通行
end note

note right of 黃色
  準備停下
end note
@enduml

✅ 如何使用:
前往 https://www.plantuml.com/plantuml,貼上程式碼,然後按「產生」。

🖼️ 輸出:一個乾淨、具有動畫效果的狀態機圖。


🎯 範例 2:具現實感的交通號誌,帶有行人請求功能

最具教育意義的版本—— 引入了守衛、自轉移和複雜邏輯。

🧠 實際應用:

  • 行人按下按鈕以穿越道路。

  • 如果有人等待,信號燈會延長等待時間。

  • 綠燈結束後,會轉為黃燈 → 紅燈 → 行人通行 → 閃爍的禁止通行 → 回到綠燈。

📌 關鍵狀態:

  1. 車輛綠燈-無需求—— 綠燈,無行人等待

  2. 車輛綠燈-行人等待—— 綠燈,有人按下了按鈕

  3. 車輛黃燈—— 黃燈(禁止通行)

  4. 全紅—— 安全緩衝(極短)

  5. 行人通行—— 行人通行標誌亮起

  6. 行人清場—— 閃爍的禁止通行(清場時間)


🧩 關鍵轉移:

  • 行人按鈕—— 如果未等待 → 設定需求

  • 定時器到期—— 轉為黃燈(若綠燈時間已達)

  • 行人按鈕—— 在黃燈/紅燈期間 → 記住需求

  • 計時器行走 → 轉至閃爍的「禁止穿越」

  • 計時器清場 → 重置並返回綠燈

🚨 注意:此版本使用守衛條件與自我轉移,顯示為何狀態機如此強大.


✅ PlantUML 程式碼(完全可運作,可直接使用):

@startuml
skinparam monochrome true
skinparam shadowing false
skinparam dpi 120

[*] --> VehicleGreen_NoDemand

state "車輛綠燈n(無行人需求)" as VG_No
state "車輛綠燈n(行人等候中)" as VG_Wait
state "車輛黃燈" as VYellow
state "全紅n(安全緩衝)" as AllRed
state "行人行走" as PedWalk
state "行人清場n(閃爍禁止穿越)" as PedClear

VG_No --> VG_Wait : pedButton / setPedDemand = true
VG_No --> VYellow : after(35s)nor (pedDemand && minGreenTimeMet)
VG_Wait --> VYellow : after(45s)n行人等候時延長綠燈
VG_Wait --> VG_Wait : pedButton / 忽略(已等候)
VYellow --> AllRed : after(4s)
AllRed --> PedWalk : after(1s)
PedWalk --> PedClear : after(10s)n行走時間結束
PedClear --> VG_No : after(5s)n清場完成n/ resetPedDemand

note bottom of VG_No
  正常運作
  無行人需求
end note

note right of PedClear
  行人完成穿越
  閃爍禁止穿越訊號
end note

note right of VG_Wait
  行人按下按鈕
  綠燈最多延長10秒
end note

note right of VYellow
  準備停止
  車輛燈號切換
end note

note right of PedWalk
  行走訊號亮起
  行人可穿越
end note
@enduml

💡 為何此版本優於簡單版本?

  • 顯示現實世界的複雜性

  • 示範守衛條件 (若行人需求存在)

  • 使用自我轉移 (VG_Wait --> VG_Wait)

  • 模擬真實行為:綠燈可延長!

  • 明確區分車輛 和 行人 邏輯


🎓 推薦練習題(按順序完成)

# 範例 時間 學到的技能
1 燈開關(開 ↔ 關) 5 分鐘 基本轉換
2 閘機(鎖定 ↔ 解鎖) 10 分鐘 事件、守衛
3 交通燈(三狀態循環) 10 分鐘 定時器、進入動作
4 自動販賣機(等待 → 支付 → 出貨) 15 分鐘 多個事件、金錢邏輯
5 登入(空白 → 輸入 → 提交 → 成功/失敗) 15 分鐘 錯誤處理、最終狀態
6 訂單狀態(6 種狀態) 20 分鐘 現實生活中的系統模擬

✅ 從 #1–3 開始在紙上或 draw.io 中進行。然後使用 PlantUML 進行剩下的部分。


🧠 成功的最後建議

  • 從小處著手 —— 不要試圖一次包含所有內容。

  • 使用真實名稱 — 等待硬幣,而不是 狀態1.

  • 清楚標示轉移 — 按鈕被按下逾時付款失敗.

  • 先用手繪製 —— 然後轉為數位格式。

  • 在腦中測試:「這個系統會卡住嗎?」→ 如果是,就增加一個轉移。


📌 總結:你的狀態機檢查清單

✅ 一個 [*] (初始狀態)
✅ 圓角矩形表示狀態
✅ 箭頭表示轉移
✅ 箭頭上的事件(30秒後行人按鈕)
✅ 必要時加上守衛條件([行人需求])
✅ 自轉移用於重複動作
✅ 進入/離開動作用於行為
✅ 清晰的版面,易讀的字型


🎯 最後的話:你已經準備好了!

你剛才學到了:

  • 什麼是狀態機圖

  • 如何以狀態與事件思考

  • 如何繪製閱讀像專家一樣

  • 如何模擬真實系統例如交通號誌

  • 如何使用 PlantUML撰寫乾淨且易於維護的圖表

🎉 你不僅僅在學習UML——你正在學習如何模擬真實系統一次一個狀態。


📌 下一步(你的學習路徑)

  1. 手繪三狀態交通號誌——不使用工具,僅用紙張。

  2. 試試PlantUML使用上方的程式碼——看看它如何呈現。

  3. 修改:更改等待時間。新增「緊急覆蓋」狀態。

  4. 試試自動販賣機→ 相同邏輯,但加入金錢因素。

  5. 繪製你自己的:一個遊戲角色(行走 → 跳躍 → 攻擊 → 死亡)。

💬 需要幫助嗎?試試這樣說:「我正在嘗試模擬一個[你的系統]——你能幫我建立一個狀態機嗎?」


🙌 最後的想法

🔄 所有會變化的東西——無論是燈、登入,還是訂單——都可以用狀態機來模擬。
你不需要是程式設計師也能理解它。你只需要問:問:「這個東西可能處於什麼狀態,又是什麼讓它改變?」


✅ 現在你已經知道如何建立專業且實用的狀態機圖——從初學者進階為自信的建模者。

🎉 祝你繪圖愉快!
如果需要可列印的PDF版本、測驗,或編碼挑戰來測試你的技能,請告訴我。


Leave a Reply