狀態模式 允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類。 簡單的解釋一下: 第一部分的意思是將狀態封裝成獨立的類,並將請求委托給當前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。 第二部分是從客戶的角度來看,我們使用的對象,在不同的狀態下具有截然不同的行為,這個 ...
狀態模式
允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類。
簡單的解釋一下:
- 第一部分的意思是將狀態封裝成獨立的類,並將請求委托給當前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。
- 第二部分是從客戶的角度來看,我們使用的對象,在不同的狀態下具有截然不同的行為,這個對象看起來是從不同的類中實例化而來的,實際上這是使用了委托的效果。
現在舉一個網上比較多的例子,沒錯就是電燈的例子(不要煩,請耐心往下看)
// 首先定義了一個Light類
class Light {
// 定義一個狀態變數
constructor(){
this.state = 'off'
}
// 定義一個改變狀態的方法
change(){
if(this.state === 'off'){
console.log('開燈')
this.state = 'on'
} else {
console.log('關燈')
this.state = 'off'
}
}
}
// 創建實例
let light = new Light()
// 調用方法
light.change()
噹噹噹噹,到此我們已經編寫了一個狀態機,邏輯簡單又縝密,看起來還有那麼點無懈可擊。BUT,你懂的事實並非如此,人生也沒那麼多的如意。隨著人類的進步,需求也不(de) 斷(cuo) 進(jin) 步(chi)(●'◡'●),於是新的電燈出現了,這電燈可厲害了,第一次點擊弱光,再次點擊強光,再點七彩光,再點emmm關了。
按我們上面的邏輯來寫,那可就刺激了:
- 首先違反了開閉原則,每次改動都要更改change()方法,使得方法變得不穩定
- 狀態切換的不明顯,無法一目瞭然的明白一共有多少種狀態
- 狀態之間的切換關係,不過是往change()方法里添加if、else語句,是change()方法更加難閱讀和維護
那怎麼辦呢?有首歌怎麼唱來著“新的電燈已經出現,怎麼能夠停滯不前”,哈哈,所以狀態模式來了~~~
因為電燈的例子太無聊了,所以我換了一個例子但是呢意思是一樣滴:
// 單曲迴圈類
class SingleCycle{
constructor(self){
this._self = self
}
modeSwitch(){
console.log('現在是單曲迴圈')
this._self.setState( this._self.listCirculation )
}
}
// 列表迴圈類
class ListCirculation{
constructor(self){
this._self = self
}
modeSwitch(){
console.log('現在是列表迴圈')
this._self.setState( this._self.sequentialPlay )
}
}
// 順序播放類
class SequentialPlay{
constructor(self){
this._self = self
}
modeSwitch(){
console.log('現在是順序播放')
this._self.setState( this._self.shufflePlay )
}
}
// 隨機播放類
class ShufflePlay{
constructor(self){
this._self = self
}
modeSwitch(){
console.log('現在是隨機播放')
this._self.setState( this._self.singleCycle )
}
}
// 音樂類
class Music{
constructor(){
// 為每個狀態都創建一個狀態對象
this.singleCycle = new SingleCycle(this)
this.listCirculation = new ListCirculation(this)
this.sequentialPlay = new SequentialPlay(this)
this.shufflePlay = new ShufflePlay(this)
// 定義初始狀態為順序播放
this.currState = this.sequentialPlay
}
// 切換播放模式
changeMode(){
this.currState.modeSwitch()
}
// 下一次點擊時的播放狀態
setState(newState){
this.currState = newState;
}
}
// 實例化音樂類
let music = new Music()
// 調用切換播放模式方法
music.changeMode()
好了,到此我們改編完成,如果你沒有懵掉,good,如果你懵掉了,往下看:
- 首先我們定義了4個狀態類
SingleCycle(單曲迴圈)
、ListCirculation(列表迴圈)
、SequentialPlay(順序播放)
、ShufflePlay(隨機播放)
- 每個狀態類都定義了一個變數
_self
來接收Music(音樂類)
傳過來的this
,還有一個方法modeSwitch(狀態更改)
,用來改變下一次要播放的狀態 - 然後定義了一個
Music(音樂類)
,首先在裡面為每一個狀態都創建了一個狀態對象,還定義了一個變數currState
來記錄下一次點擊時的狀態。 - 最後就是Music(音樂類)裡面定義的兩種方法
changeMode(切換播放模式)
、setState(下一次點擊時的播放狀態)
。當我們點擊切換模式的時候,在changeMode(切換播放模式)
中去調用之前定義好的狀態類中的modeSwitch(狀態更改)
方法,完成模式切換的同時調用Music(音樂類)中的setState(下一次點擊時的播放狀態)
方法來對狀態進行改變,保證下一次點擊時切換不同的模式。
通過上面的方法可以看出:
- 我們可以在
Music(音樂類)
中清楚的知道一共有多少個狀態,同時Music(音樂類)
中不再進行任何實質性的操作,而是通過this.currState.modeSwitch()
交給了當前持有的狀態對象去執行 - 狀態的切換規律被事先在每一個狀態類中定義好了,在
Music(音樂類)
中沒有任何一個和狀態切換相關的條件分支語句
悄悄地說,上面的方法還闊以再完美一點呦
小小的拓展
通過上面的介紹我們瞭解到了每一個狀態類都有一個 modeSwitch()
方法,也就意味著我們每次添加狀態類都要寫一個方法,問題來了,人非聖賢,孰能無過?所以咧難免會丟掉的嘛!
然後做一些小小的優化:
// 定義一個State類
class State{
constructor(self){
this._self = self
}
modeSwitch(){
throw new Error( '父類的 modeSwitch 方法必須被重寫' )
}
}
// 狀態類(舉一個為例)
// 單曲迴圈類(繼承State類)
class SingleCycle extends State{
modeSwitch(){
console.log('現在是單曲迴圈')
this._self.setState( this._self.listCirculation )
}
}
好了完成,當某一天我們忘了寫方法,也能夠快速的定位到錯誤
目前對於狀態模式的理解就這麼多,以後有了新的理解會繼續更新的,溜了溜了(~ ̄▽ ̄)~