我們昨天透過一個 object 描述一個狀態機的定義,還記得前天我們的 switch / case
做出的 transition function 嗎?transition function 是一個 純函式(pure function),我們還缺少一個東西來儲存當前的狀態。
State Machine 不完全,沒有一個變數能幫我記憶當下的狀態是什麼,我在使用 transition 時還要另外用一堆變數來儲存 state ,感覺不好維護、也不好維持程式碼的連貫性
試著思考看看 有個 function 叫做 createMachine
,當我們把 狀態機的定義 machineDef
丟進去,他就可以回傳給我們一個能儲存狀態的狀態機
someMachine = createMachine(someMachineDef)
那我們這個 someMachine 會需要有哪些東西?
by The Finite State of Reactive Animations
[x] Initial State,
[x] States,
[x] Events,
[_] Transition,
[_] Final States (可能沒有)
上面 [x] 這些東西已經在昨天被我們寫進 machineDef
,那我們應該還缺的是 transition function 跟能儲存當下狀態的 Current State
為了儲存狀態 Current State,程式開發中,目前所知具有狀態性,能儲存狀態的值也是「物件」,所以我們決定採用物件,這個物件會依照 machineDef
當作 configuration。
假設我們希望 someMachine.state
可以拿到當前狀態, someMachine.transition('事件')
可以轉移狀態,所以我們的透過 function 回傳一個物件,實作可以長這樣
function createMachine(machineDef) {
return {
// 初始值是 initialState 我們透過這個 object 儲存 state
state:machineDef.initialState,
// 實作 transition
transition(event){
...
}
}
}
那新版的 transition 該怎麼實作,先來看看我們手上有什麼材料,一起來看看昨天的 machineDef
const machineDef = {
initialState: "站姿、靜止",
states: {
"站姿、靜止": {
on: {
跳躍: "跳躍中",
.....
我們可以從 machineDef.states[state]
拿到當前狀態下所有事件對應該的轉換,下個也就是我們昨天說的那個名為 on 的 transition mapping
所以繼續往下走,接著可以透過 machineDef.states[state].on[event]
,取得發生某個的事件後要轉成的狀態。
所以我們的 transition
應該可以這樣實作,拿到物件的 Current State ,以及使用者要執行的事件 Event
transition(event){
const nextState = machineDef.states[this.state]?.on[event]
this.state = nextState
return this.state
}
然後可能查找失敗,當我們拿不到值,transition 不能正確轉換、或說不應該轉換,此時,我們應該就要維持原本的狀態
因為 nextState = transition(previousState, event)
的 previusState, event,只要其中一個是不符的話,代表我們不能改變狀態。
transition(event){
const nextState = machineDef.states[this.state]?.on[event]
if(nextState){
this.state = nextState
}
return this.state
}
如此我們就完成了一個簡單的 state machine
function createMachine(machineDef) {
return {
// 初始值是 initialState 我們透過這個object 儲存 state
state:machineDef.initialState,
// 實作 transition
transition(event){
const nextState = machineDef.states[this.state]?.on[event]
if(nextState){
this.state = nextState
}
return this.state
}
}
}