jQueryとJavaScript(CoffeeScript)を使った開発をしていて、ユーザーからの入力のイベント処理とAjaxによる通信のイベント処理がごちゃごちゃになって困ったことはありませんか?
私は最近までよくフラグだらけになる失敗をしました。
このような問題を解決する道具のひとつとしてステートマシンがあります。
CoffeeScriptを使って試行錯誤した結果、短く簡単に作れるようになったので紹介してみたいと思います。
demo_state_machine.coffeeはサンプルのソースコードです。
DemoSMがステートマシンで、アクションのハッシュを引数にして関数として呼び出します。
ステートマシンに対してイベントを送る(sm().ev1(), sm().ev2()などをコールする)と、内部のステートが変わりアクションが実行されます。
デバッグモードも用意してあり、sm.setDebugMode(true)すると、内部のステートの遷移がコンソールに出力されます。
DemoSM = (actions) ->
currentState = null
inTransition = false
debugMode = false
setState = (state) ->
throw 'Recursive call of setState is forbidden' if inTransition
inTransition = true
currentState.Exit() if currentState
currentState = state
console.log "ENTER STATE: #{state.name()}" if debugMode
currentState.Entry()
inTransition = false
defaultAction = -> null
class StateBase
name: -> 'StateBase'
Entry: defaultAction
Exit: defaultAction
ev1: defaultAction
ev2: defaultAction
STATE1 = new class extends StateBase
name: -> 'STATE1'
Entry: -> actions.onEntry 'STATE1'
Exit: -> actions.onExit 'STATE1'
ev1: -> setState STATE2
STATE2 = new class extends StateBase
name: -> 'STATE2'
Entry: -> actions.onEntry 'STATE2'
Exit: -> actions.onExit 'STATE2'
ev2: -> setState STATE1
setState STATE1
self = -> currentState
self.setDebugMode = (mode) -> debugMode = mode
self.isDebugMode = -> debugMode
self.isInTransition = -> inTransition
self
sm = DemoSM
onEntry: (name) -> console.log "#{name}: onEntry"
onExit: (name) -> console.log "#{name}: onExit"
sm.setDebugMode true
sm().ev1()
sm().ev1()
sm().ev1()
sm().ev2()
sm().ev1()
動作の確認は、開発環境を用意しなくてもWeb上から行うことが出来ます。
サンプルであげたようなソースコードを定義ファイルから自動生成するツールを作成中なので、もしも需要がありそうなら公開したいと思います。