---
# System prepended metadata

title: 狀態機

---

有限狀態機(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)