狀態模式
工作中,常常使用到狀態機,如何才能把一個流程確定的狀態機代碼編寫好,恰恰是狀態模式要解決的問題。
假設目前有一個場景,一個按鈕有A B C三種狀態,狀態切換的流程為 A -> B -> C -> A...
按鈕在不同的狀態下面,按鈕執行不同的點擊動作,如何去編寫者一塊代碼?
一般的編寫思路為
// html <button id="button">click</button>
var state = {A: 1, B: 2, C: 3};
var currentState = state.A; //default
var button = document.getElementById("button");
button.onclick = function() {
if (currentState === state.A) {
console.log('operating in state A');
currentState = state.B;
} else if (currentState === state.B) {
console.log('operating in state B');
currentState = state.C;
} else if (currentState === state.C) {
console.log('operating in state C');
currentState = state.A;
} else {
throw new Error("can not find the state");
}
}
上面的寫法有什么問題嗎?當然是有的,多個狀態全部用if else判斷,如果新增狀態的話,是不是要修改這個onclick函數,而且如果在不同的狀態下,做的邏輯比較復雜的話,是不是onclick函數會顯得臃腫許多。
有沒有更好的辦法呢?
- 使用狀態模式,狀態模式要解決的問題是,在當前的狀態下面,就直接做這個動作,而不是判斷是否處于這個狀態下面,去做這個動作,類似于多態,不管你當前是啥,反正我直接調用你這個動作執行的方法就行了,
- 在狀態模式使用的過程中,我們一般使用委托,把當前需要做的動作,直接委托到當前這個狀態的對象的動作中來,無需判斷當前是處于哪個狀態,所以狀態對象提供的動作接口必須是一致的
狀態模式改進版
// 為了向上提供一致的接口,每個狀態執行的動作函數名稱必須一致
var FSM = {
A: {
//我只是關心A狀態下面 會做什么
handler: function() {
console.log('operating in state A');
currentState = FSM.B;
}
},
B: {
handler: function() {
console.log('operating in state B');
currentState = FSM.C;
}
},
C: {
handler: function() {
console.log('operating in state C');
currentState = FSM.A;
}
}
}
var currentState = FSM.A; //default
var button = document.getElementById("button");
button.onclick = function() {
currentState.handler.call(this);
//把當前的onclick委托給 現在狀態的handler
//這里我不關心當前這個狀態是什么,我只是關心當前這個狀態會發生什么,所以去除了if else
}
完整代碼:
<!DOCTYPE html>
<html>
<head></head>
<body>
<button id="button">click</button>
<script type="text/javascript">
// 為了向上提供一致的接口,每個狀態執行的動作函數名稱必須一致
var FSM = {
A: {
//我只是關心A狀態下面 會做什么
handler: function() {
console.log('operating in state A');
currentState = FSM.B;
}
},
B: {
handler: function() {
console.log('operating in state B');
currentState = FSM.C;
}
},
C: {
handler: function() {
console.log('operating in state C');
currentState = FSM.A;
}
}
}
var currentState = FSM.A; //default
var button = document.getElementById("button");
button.onclick = function() {
currentState.handler.call(this);
//用call的目的是 如果狀態里面想要當前對象的話,可以把當前對象 this傳遞過去
//把當前的onclick委托給 現在狀態的handler
//這里我不關心當前這個狀態是什么,我只是關心當前這個狀態會發生什么,所以去除了if else
}
</script>
</body>
</html>