1. 簡介
狀態模式(State)允許一個物件在其內部狀態改變的時候改變它的行為,物件看起來似乎修改了它的類。
其實就是用一個物件或者陣列記錄一組狀態,每個狀態對應一個實現,實現的時候根據狀態挨個去執行實現。
2. 實現
比如超級瑪麗,就可能同時有好幾個狀態比如 跳躍,移動,射擊,蹲下 等,如果對這些動作一個個進行處理判斷,需要多個if-else
或者switch
不僅醜陋不說,而且在遇到有組合動作的時候,實現就會變的更為複雜,這裡可以使用狀態模式來實現。
狀態模式的思路是:首先建立一個狀態物件或者陣列,內部儲存狀態變數,然後內部封裝好每種動作對應的狀態,然後狀態物件返回一個介面物件,它可以對內部的狀態修改或者呼叫。
const SuperMarry = (function() {
let _currentState = [], // 狀態陣列
states = {
jump() {console.log('跳躍!')},
move() {console.log('移動!')},
shoot() {console.log('射擊!')},
squat() {console.log('蹲下!')}
}
const Action = {
changeState(arr) { // 更改當前動作
_currentState = arr
return this
},
goes() {
console.log('觸發動作')
_currentState.forEach(T => states[T] && states[T]())
return this
}
}
return {
change: Action.changeState,
go: Action.goes
}
})()
SuperMarry
.change(['jump', 'shoot'])
.go() // 觸發動作 跳躍! 射擊!
.go() // 觸發動作 跳躍! 射擊!
.change(['squat'])
.go() // 觸發動作 蹲下!
這裡可以使用ES6
的class
優化一下:
class SuperMarry {
constructor() {
this._currentState = []
this.states = {
jump() {console.log('跳躍!')},
move() {console.log('移動!')},
shoot() {console.log('射擊!')},
squat() {console.log('蹲下!')}
}
}
change(arr) { // 更改當前動作
this._currentState = arr
return this
}
go() {
console.log('觸發動作')
this._currentState.forEach(T => this.states[T] && this.states[T]())
return this
}
}
new SuperMarry()
.change(['jump', 'shoot'])
.go() // 觸發動作 跳躍! 射擊!
.go() // 觸發動作 跳躍! 射擊!
.change(['squat'])
.go() // 觸發動作 蹲下!
3. 總結
狀態模式的使用場景也特別明確,有如下兩點:
- 一個物件的行為取決於它的狀態,並且它必須在執行時刻根據狀態改變它的行為。
- 一個操作中含有大量的分支語句,而且這些分支語句依賴於該物件的狀態。狀態通常為一個或多個列舉常量的表示。
簡而言之,當遇到很多同級if-else
或者switch
的時候,可以使用狀態模式來進行簡化。
本文是系列文章,可以相互參考印證,共同進步~
網上的帖子大多深淺不一,甚至有些前後矛盾,在下的文章都是學習過程中的總結,如果發現錯誤,歡迎留言指出~
參考:
《Javascript 設計模式》 - 張榮銘
設計模式之狀態模式