Blackbing Playground

有限狀態機

javascript 是 Event Based 的語言,因此可以很輕易的實作事件綁定來處理非同步的動作,為了將表現層與資料層分離,就會用「值」的改變來 trigger 事件。例如在 Backbone Model 裡頭可以做 change:value 的事件處理。例如:

1
book.on("change:title change:author", ...);

但是隨著應用程式越來越複雜,value 的 change 可以拿來當作事件的觸發,但流程並不會因此簡化,在設計程式時如果沒有一個更清晰的流程將會在 Event 裡頭的流程迷失方向,或寫出難以維護的程式碼。

Event pubsup

Event Pubsub,利用事件 publish/subscribe 的方式來做流程處理。但 pubsup只是針對事件的「綁定」與「觸發」,缺少了「狀態的轉換」。

有限狀態機(Finite State Machine)

有限狀態機」是描述一種狀態的轉移,它強調過去狀態與當前狀態所引發的事件,因此可以將流程簡化到事件的處理之中。而且將流程簡化出來也能夠幫助自己在分析時更清楚地掌握流程處理。所以有限狀態機的重點是要將現有的流程簡化成一個可循環的狀態,利用狀態的轉移來觸發事件,相反地也可以觸發事件來轉移狀態。

javascript-state-machine

javascript-state-machine 是我覺得很好用的一套小 library ,程式碼也沒有很長,有興趣可以研究看看。裡頭有一個小 Demo,簡單解釋一下。

see demo: http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/example/

條件如下:

  1. 初始化事件:green
  2. warn: green -> yellow
  3. panic: green/yellow -> red
  4. 當 red 時,calm 事件觸發時要等待三秒才會恢復到 yellow
  5. 當 red 時,clear 事件觸發時要等待三秒才會恢復到 green
  6. 當 yellow 時,clear 事件觸發會恢復到 green

流程圖

看敘述有點難理解,可以直接看流程圖
Screen Shot 2013-11-07 at 下午1.09.47.png

事件:

  • start
  • warn
  • panic
  • calm
  • clear

流程:

  • reen
  • yellow
  • red

如果只看事件的話,只能依靠事件的觸發來控制流程,但是加上「狀態」之後,看起來就好理解多了,而且整個是一個可以循環的流程。把事件用箭頭連起來,就可以知道何時可以觸發哪一個事件。

流程圖中的箭頭代表「事件」轉換,框框代表「狀態」的轉移,所以當「狀態」改變,就會觸發「事件」,反之「事件」被觸發,就會改變「狀態」。例如「Warn事件」發生的時候,狀態就會從 green 轉移至 yellow;而「Panic事件」發生時,狀態就會改變成 red。

而設定的方式也很直覺,在 event 的地方設定好事件觸發時狀態如何改變。而 callbacks 可以在事件被觸發前/後 執行 callback unction。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
events: [
{ name: 'start', from: 'none', to: 'green' },
{ name: 'warn', from: 'green', to: 'yellow' },
{ name: 'panic', from: 'green', to: 'red' },
{ name: 'panic', from: 'yellow', to: 'red' },
{ name: 'calm', from: 'red', to: 'yellow' },
{ name: 'clear', from: 'red', to: 'green' },
{ name: 'clear', from: 'yellow', to: 'green' },
],
callbacks: {
onbeforestart: function(event, from, to) { log("STARTING UP"); },
onstart: function(event, from, to) { log("READY"); },
onbeforewarn: function(event, from, to) { log("START EVENT: warn!", true); },
onbeforepanic: function(event, from, to) { log("START EVENT: panic!", true); },
onbeforecalm: function(event, from, to) { log("START EVENT: calm!", true); },
onbeforeclear: function(event, from, to) { log("START EVENT: clear!", true); },
onwarn: function(event, from, to) { log("FINISH EVENT: warn!"); },
onpanic: function(event, from, to) { log("FINISH EVENT: panic!"); },
oncalm: function(event, from, to) { log("FINISH EVENT: calm!"); },
onclear: function(event, from, to) { log("FINISH EVENT: clear!"); },
onleavegreen: function(event, from, to) { log("LEAVE STATE: green"); },
onleaveyellow: function(event, from, to) { log("LEAVE STATE: yellow"); },
onleavered: function(event, from, to) { log("LEAVE STATE: red"); async(to); return false; },
ongreen: function(event, from, to) { log("ENTER STATE: green"); },
onyellow: function(event, from, to) { log("ENTER STATE: yellow"); },
onred: function(event, from, to) { log("ENTER STATE: red"); },
onchangestate: function(event, from, to) { log("CHANGED STATE: " + from + " to " + to); }
}

不過實際上,有限狀態機可以做什麼用?待續…

#延伸閱讀: