有限狀態機(Finite State Machine, FSM) - Bear Wang 🐻 === [TOC] ## What is ==狀態機==? > **狀態機**是一個抽象的機器或系統模型,也是一個強大的思維工具 狀態機就像是一個會變化的系統,它可以處於不同的單一狀態,根據發生的事件或特定條件,從一個狀態切換到另一個。 > :包含**狀態**、**事件**、**轉換**和**動作**四個基本要素。 如果以不同的分類標準來定義的話,有各種不同的狀態機分類。 🚩 **以狀態==數量==分類的狀態機有:** :::info ### **有限狀態機(Finite State Machine,FSM)** --- - 定義: - 具有**有限數量**的狀態 - 狀態轉換規則明確且固定 - 所有可能的狀態都可以預先定義 - 運用情境: - 訂單處理系統(待付款→已付款→已發貨→已完成) - 遊戲狀態控制(開始→暫停→結束) - 電梯控制系統(上行→停止→下行) - 交通信號燈控制(紅→黃→綠) - etc ... ::: :::info ### **無限狀態機(Infinite State Machine,ISM)** --- - 定義: - 可能具有無限數量的狀態 - 狀態數量是動態的或不可預知的 - 轉換規則可能動態變化 - 運用情境: - 計數器系統(數值可以無限增長) - 動態內存管理(內存分配狀態) - 實時數據流處理(持續接收新數據) - etc ... ::: :::warning **主要差異** --- | 特點 | 有限狀態機(FSM) | 無限狀態機(ISM) | | --- | --- | --- | | 狀態數量 | 有限且固定 | 無限或動態 | | 可預測性 | 高 | 相對較低 | | 實現複雜度 | 較簡單 | 較複雜 | | 資源消耗 | 較少 | 較多 | | 適用場景 | 明確且有限的業務流程 | 動態變化的系統 | ::: > 實務上 我們通常在說狀態機的時候泛指 **有限狀態機** ## Why do we need to learn about "有限狀態機" 學習有限狀態機(FSM)的核心價值可以總結為三大面向: #### 1. 系統思維的建立 - 提供清晰的邏輯框架,將複雜問題分解為可理解的狀態 - 培養系統性思考方式,強化問題分析能力 - 有助於預測和控制系統行為,提升決策品質 #### 2. 實務應用的效益 - 程式設計更有條理,維護和除錯更容易 - 需求分析和流程設計更準確 - 系統擴展性好,新功能整合更順暢 - 提升團隊溝通效率,降低誤解成本 #### 3. 跨領域的通用價值 - 從工程師到產品經理都能受益 - 適用於軟體開發、流程管理、產品設計等多個領域 - 提供通用的思維模型,促進跨部門協作 - 有助於業務流程優化和風險管理 ![image](https://hackmd.io/_uploads/SyI1_bJYkg.png) 簡單來說,FSM不只是一個技術概念,而是一種強大的思維工具, 幫助我們將複雜的問題或系統分解成清晰的==狀態==和==轉換規則==,不僅適用於程式設計,更可應用於生活中各種場景的系統化思考和問題解決。 ![image](https://hackmd.io/_uploads/H1lWgMwFyl.png) ## What is 有限狀態機 (Finite State Machine, FSM) :::info ### 定義: --- - 具有==有限==數量的狀態 - 狀態轉換規則明確且固定 - 所有可能的狀態都可以預先定義 ::: :::info ### 基本要素: --- - **狀態(States)**: 系統擁有明確且有限數量的狀態,每個狀態代表系統在特定時刻的情況。 - **事件/轉換條件(Events / Transition Condition)**: 系統能夠識別並接收預先定義的事件或輸入,這些事件會觸發狀態的改變。 - **轉換(Transitions)**: 系統遵循固定且明確的規則,根據當前狀態和接收到的事件決定如何轉換到下一個狀態。 - **動作(Actions)**: 在特定狀態下或狀態轉換過程中,系統會執行預先定義的相應動作或行為。 ::: :::info #### 簡例說明 用按鈕或感應器控制大門的打開或關閉。 --- ![image](https://hackmd.io/_uploads/SkLCuSeYyx.png) | 項目 | 說明 | 解釋 | |------------------------------|------------------------------|-------------------------------------------------------------| | **狀態 (State)** | - 門開著<br>- 門關著 | - 狀態代表系統的當前情況或條件<br>- 系統在任一時刻只能處於一個狀態<br>- 門只能是「開啟」或「關閉」<br>- 門系統永遠處於這兩個狀態之一 | | **事件 (Event)** `轉換條件` | - 開門指令信號<br>- 關門指令信號 | - 事件是觸發狀態改變的**外部輸入**<br>- 可能來自按鈕、感應器或刷卡等<br>- 事件促使系統從一個狀態轉換到另一個 | | **轉換 (Transition)** | - 門關著 → 門開著 <br>- 門開著 → 門關著 | - 定義了狀態之間如何切換<br>- 箭頭指示狀態改變的方向<br>- 轉換必須有明確的觸發事件 | | **動作 (Action)** | - 門開著狀態:啟動開門馬達<br>- 門關著狀態:啟動關門馬達 | - 進入某狀態時系統執行的具體行為<br>- 例如進入「開啟狀態」時,馬達自動啟動<br>- **動作是系統行為自動執行的,不需要額外觸發** | --- 上面的例子是一個最基本的FSM,他滿足了FSM的基本條件 - 兩個明確的狀態 - 清晰的轉換條件 - 狀態間的轉換關係 - 每個狀態的進入動作 ::: :::spoiler 🫤: 老師~ [事件] 和 [動作] 容易搞混怎麼辦? :::danger #### 溫腥小提醒 容易搞混的 **事件** `Event/Transition Condition` v.s. **動作** `Action` 要怎麼分辨呢? --- ![image](https://hackmd.io/_uploads/BkwLzUgtkg.png) 🤨 可以看到這個示意圖的 **[開門]** 與 **[關門]** 同時是**動作**,也是**事件**!? 那到底他們的差別是什麼呢? | 類別 | 說明 | 具體表達方式 | |--------|------------------------------|------------------------------| | **事件 (Events)** | - 這裡`開門` 和 `關門`:「觸發條件」 <br>- 事件是**輸入**`是促使狀態改變的觸發因素`<br>- ex.按鈕、感應器、遙控信號etc. | - **收到開門信號**(而不是簡單的`開門`)<br>- **收到關門信號**(而不是簡單的`關門`) | | **動作 (Actions)** | - 這裡`開門` 和 `關門`:「系統行為」<br>- 動作是**輸出**`進入狀態後系統要做的行為`<br>- ex.啟動馬達、提示聲音etc. | - **啟動開門馬達**(具體的系統行為)<br>- **啟動關門馬達**(具體的系統行為) | --- :bulb: - 事件(Event / Transition Condition) 是**系統的輸入(接收)** - 動作(Action) 是**系統的輸出(執行)** 兩者雖然可能描述相似的概念,但在FSM中扮演不同的角色 ::: :::info ### 動作(Action) 而 **動作**, 在不同時機執行的動作又可以分成四種 --- - **進入動作** (Entry Action): 進入這個狀態時,會執行什麼工作? - **離開動作** (Exit Action): 離開這個狀態時,會執行什麼工作? - **輸入動作** (Input Action): 處於某狀態時,收到事件會執行什麼動作? `(即執行動作但不轉變狀態)` - **轉移動作** (Transition Action): 轉移狀態過程中,會執行什麼動作? --- - FSM的動作執行時機分兩種狀況來說明: 1. 狀態會改變 2. 狀態不改變 ![image](https://hackmd.io/_uploads/r1zyyqgKJe.png) ![image](https://hackmd.io/_uploads/r1wxy9gKkg.png) --- #### 狀態機執行流程說明: - 系統處於某個狀態時,可以接收各種事件 - 根據接收到的事件,決定是否需要改變狀態 - 如果需要改變狀態,依序執行以下動作: 1. [輸入動作] `在原狀態下` 接收到事件執行 2. [離開動作] `在原狀態下` 狀態改變前執行 3. [轉移動作] `此過程中狀態逐漸改變` ==不屬於原狀態也不是新狀態== 4. [進入動作] `在新狀態下` - 如果不需要改變狀態,則只執行[輸入動作] - 完成動作執行後,系統進入新狀態或維持原狀態 --- #### 重要提示: 1. 當需要狀態改變時(路徑A):轉移動作是必要的,其他動作皆為可選 2. 當不需要狀態改變時(路徑B):只執行輸入動作,不需要其他動作 3. 執行順序(路徑A):輸入動作 → 離開動作 → 轉移動作 → 進入動作 ::: ## Example :::success ### :traffic_light: 範例 #### 需求 我要做一個紅綠燈功能。 需要具備紅、黃、綠三種燈號,且必須能夠依序自動切換燈號。 - 紅燈亮40秒 - 紅燈轉黃燈,黃燈亮5秒 - 黃燈轉綠燈,綠燈亮60秒 - 綠燈轉黃燈,黃燈亮10秒 - 黃燈轉回紅燈,循環重新開始 --- #### 元素 1. **狀態 (States)**: 系統在任何時刻都只能處於三種狀態之一:紅燈、黃燈或綠燈 - 紅燈 :heart: - 黃燈 :yellow_heart: - 綠燈 :green_heart: 2. **事件 (Events / Transition Condition)**: 系統通過計時器觸發狀態改變 - 紅燈計時器到達40秒 - 黃燈計時器到達5秒(紅轉綠時) - 綠燈計時器到達60秒 - 黃燈計時器到達10秒(綠轉紅時) 3. **轉換 (Transitions)**: 每次轉換都遵循固定的順序和時間 - :heart: 紅燈 (40秒後)→ :yellow_heart: 黃燈 - :yellow_heart: 黃燈 (5秒後)→ :green_heart: 綠燈 - :green_heart: 綠燈 (60秒後) → :yellow_heart: 黃燈 - :yellow_heart: 黃燈(10秒後) → :heart: 紅燈 4. **動作 (Actions)**: 系統在不同時機執行四種動作: - 輸入動作:檢查計時器、更新顯示 - 離開動作:關閉當前燈號、記錄狀態 - 轉移動作:執行實際的燈號切換 - 進入動作:開啟新的燈號、設定計時器 ::: :::spoiler 紅綠燈範例圖示 ![image](https://hackmd.io/_uploads/ByeBRp-tkl.png) #### [紅綠燈程式碼範例](https://codesandbox.io/p/devbox/you-xian-zhuang-tai-ji-ftm-example-vpgszm?file=%2Fsrc%2FTrafficLight.tsx%3A31%2C7-31%2C18) ::: ## 延伸:設計模式 v.s 有效狀態機 > 在程式設計中,有限狀態機(Finite State Machine, FSM) 是一種用於系統狀態轉換的方式,特別適用於行為依賴於內部狀態的應用場景。許多設計模式與 FSM 的概念相似或直接應用於 FSM 的實作,以下是幾種最相關的設計模式: :::info ### **1\. 狀態模式(State Pattern)** **關聯性:** 狀態模式直接對應 FSM,透過定義不同的「狀態類別」,讓物件可以在不同狀態間切換,避免使用大量的 `if-else` 或 `switch-case` 來處理狀態變化。 **範例應用:** - 設計遊戲角色的狀態(如「行走」、「攻擊」、「跳躍」)。 - 管理 UI 組件的不同狀態(如「開啟」、「關閉」、「懸停」)。 --- ### **2\. 策略模式(Strategy Pattern)** **關聯性:** 策略模式與 FSM 相似之處在於,它允許在不同情境下選擇不同的行為,但它更側重於「可變行為」而非「狀態轉換」。 **範例應用:** - 根據不同的環境選擇不同的運算演算法(如 AI 行為決策)。 - 設計支付方式(如信用卡、PayPal、比特幣)。 --- ### **3\. 命令模式(Command Pattern)** **關聯性:** 命令模式允許將請求封裝為物件,可以與 FSM 結合,讓狀態機在不同狀態下選擇適當的命令來執行。 **範例應用:** - 遊戲角色的技能切換(不同狀態執行不同指令)。 - GUI 按鈕的點擊行為(不同狀態觸發不同動作)。 --- ### **4\. 觀察者模式(Observer Pattern)** **關聯性:** FSM 的狀態改變時,可能需要通知其他模組或組件進行相應動作,這與觀察者模式的機制相符。 **範例應用:** - 當玩家的生命值變化時,UI 生命條也跟著變動。 - 當電商庫存狀態變更時,通知用戶和供應商。 --- ### **5\. 責任鏈模式(Chain of Responsibility Pattern)** **關聯性:** 當 FSM 處理事件時,責任鏈模式允許請求沿著一系列處理器傳遞,直到找到適當的處理方式,類似於 FSM 的狀態轉移。 **範例應用:** - 事件處理系統(不同狀態由不同的 handler 負責處理)。 - 訊息過濾機制(依據不同狀態篩選資訊)。 --- ### 對應表 ![image](https://hackmd.io/_uploads/H14tD7aiJl.png) --- ### **結論** 有限狀態機(FSM)在許多應用場景中至關重要,而設計模式提供了一些有組織的方法來實作 FSM。其中 **狀態模式** 是最直接的 FSM 具現化方式,而 **策略模式、命令模式、觀察者模式與責任鏈模式** 則提供了不同層面的輔助,讓 FSM 的設計更加靈活、可維護。根據具體需求,開發者可以選擇最合適的模式來實作高效且可擴展的狀態機系統。 ::: ## 參考資源 - [Day 21:什麼是「有限狀態機」?](https://ithelp.ithome.com.tw/articles/10225343) - [如何有邏輯的釐清事物的狀態](https://medium.com/pm%E7%9A%84%E7%94%9F%E7%94%A2%E5%8A%9B%E5%B7%A5%E5%85%B7%E7%AE%B1/%E5%A6%82%E4%BD%95%E6%9C%89%E9%82%8F%E8%BC%AF%E7%9A%84%E9%87%90%E6%B8%85%E4%BA%8B%E7%89%A9%E7%9A%84%E7%8B%80%E6%85%8B-f9fb59b15054) - [Design Patterns](https://refactoringguru.cn/design-patterns)