---
# System prepended metadata

title: 2021 年 01 月

---

2021 年 01 月
===

### 蒼時

## 狀態機

通常就是指「有限狀態機（FSM）」在現實中大多數的情況也是屬於有限狀態機，簡單來說就是從狀態 A 切換到 B 的時候需要滿足條件，否則無法切換。

* 狀態：物件當下的狀態
* 事件：觸發改變狀態的原因
* 過度：改變狀態的過程
* 過度條件：限制狀態改變的條件

狀態機在很多地方都會被使用到，像是遊戲中的「動畫控制」就是其中一項。

> 準備了簡單的動畫控制範例跟大家分享

### 案例

門有「開啟」跟「關閉」兩種狀態，當我們「開門」的時候會進入「開門中」的過度，而要進入這個過渡的條件是「門關閉著」的狀態。

維基百科：[有限狀態機](https://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA)

## 有向無環圖（Directed Acyclic Graph）

跟狀態機類似的是 DAG 我們可以順便看一下，跟前面狀態機的圖相比起來 DAG 並不會構成「循環」也就是最終一定會在某個狀態下終止。

舉例來說，一個電商網站的訂單狀態的變化就可以用 DAG 來表示，從產生訂單到付款、完成訂單即時中間可能會因為有「失敗狀態」構成循環，但最終一定會抵達某個終點。

維基百科：[有向無環圖](https://zh.wikipedia.org/wiki/%E6%9C%89%E5%90%91%E6%97%A0%E7%8E%AF%E5%9B%BE)

## AASM

AASM 是 Ruby 的狀態機實作套件，同時也支援 ActiveRecord 在使用上基本上就是對應狀態機的設計，因此我們在使用 AASM 的時候同樣會定義以下資訊。

* 狀態 `state :idle`
* 事件 `event :walk`
* 過度 `transition from: :idle, to: :walking`

### Callback

單純的狀態機在大多數時候是不太夠用的，因此 AASM 提供了 Callback 在不同的情況下提供可以做額外處理的機會。

舉例來說 `state`（狀態）有 `exit` 和 `enter` 兩種類型事件，在從狀態 A 切換到 B 時會先呼叫狀態 A 的 `before_exit` 和 `exit` 等 Callback 來處理，而進入狀態 B 時則會呼叫 `before_enter` 和 `enter` 等 Callback 來進行特定的動作。

> 在 AASM 的設計裡面狀態、事件、過度都有預留 Callback 可以使用，呼叫的順序則需要參考網站上的列表。

### Guard

正常的情況下「過度條件」通常是前一個狀態符合要求，但某些時候我們會需要跟物件其他資訊一起判斷，也因此 AASM 提供了 Guard 的選項讓我們可以針對這類情況客製化。

### Binding Event

> 沒用過 😂

簡單說當物件有多種狀態時，可以連動另一個狀態事件一起被觸發。

### ActiveRecord 支援

在 Callback 的部分中增加了像是`after_commit` 可以在資料庫操作中被 Commit 後才呼叫（例如處理完畢後呼叫另一個 Job 接著處理）除此之外還有像是悲觀鎖（Pessimistic Locking）的機制可以打開，通常是為了確保資料再變更時不會遇到像是 Race Condition 而造成預期外的影響。




