Javascript-設計模式_狀態模式
前言
狀態模式的關鍵是區分事物內部的狀態,事物內部狀態的改變往往會帶來事物的行為改變,即物件行為是基於狀態來改變的,內部的狀態轉化,導致了行為表現形式不同
當電燈開著,此時按下開關,電燈會切換到關閉狀態;再按一次開關,電燈又將被開啟。同一個開關在不同的狀態下,表現出來的行為是不一樣的
場景條件--有限狀態機
-
狀態總數(state)是有限的
-
任一時刻,只處在一種狀態之中
-
某種條件下,會從一種狀態轉變(transition)到另一種狀態
允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類
解釋:
-
將狀態封裝成獨立的類,並將請求委託給當前的狀態物件,當物件的內部狀態發生改變時,會帶來不同的行為變化
-
使用的物件,在不同的狀態下具有截然不同的行為(委託效果)
談到封裝,一般優先考慮封裝物件的行為,而不是物件的狀態,但在狀態模式中剛好相反,狀態模式的關鍵是把事物的每種狀態都封裝成單獨的類
示例
點燈程式 (弱光 –> 強光 –> 關燈)迴圈
/* 關燈 */ const OffLightState = light => { this.light = light } /* 弱光 */ const WeakLightState = light => { this.light = light } /* 強光 */ const StrongLightState = light => { this.light = light } const Light = () => { // 開關狀態 this.offLight = new OffLightState(this) this.weakLight = new WeakLightState(this) this.strongLight = new StrongLightState(this) // 快關按鈕 this.button = null } Light.prototype.init = () => { const button = document.createElement('button') const self = this this.button = document.body.appendChild(button) this.button.innerHTML = '開關' this.currentState = this.offLight this.button.click = () => { self.currentState.buttonWasPressed() } } /* 讓抽象父類的抽象方法直接丟擲一個異常(避免狀態子類未實現buttonWasPressed方法) */ Light.prototype.buttonWasPressed = () => { throw new Error('父類的buttonWasPressed方法必須被重寫') } Light.prototype.setState = newState => { this.currentState = newState } /* 關燈 */ OffLightState.prototype = new Light() // 繼承抽象類 OffLightState.prototype.buttonWasPressed = () => { console.log('關燈!') this.light.setState(this.light.weakLight) } /* 弱光 */ WeakLightState.prototype = new Light() WeakLightState.prototype.buttonWasPressed = () => { console.log('弱光!') this.light.setState(this.light.strongLight) } /* 強光 */ StrongLightState.prototype = new Light() StrongLightState.prototype.buttonWasPressed = () => { console.log('強光!') this.light.setState(this.light.offLight) }
效能優化點
-
如何管理狀態物件的建立和銷燬
第一種僅當state物件被需要時才建立並隨後銷燬(state物件比較龐大,優先選擇)
另一種是一開始就建立好所有的狀態物件,並且始終不銷燬它們(狀態改變頻繁)
-
利用享元模式共享一個state物件
優缺點
優點
封裝了轉化規則,對於大量分支語句,可以考慮使用狀態類進一步封裝。 每個狀態都是確定的,所以物件行為是可控的
缺點
狀態模式的關鍵是將事物的狀態都封裝成單獨的類,這個類的各種方法就是“此種狀態對應的表現行為”, 因此狀態類會增加程式開銷
總結
狀態模式的使用場景也特別明確,有如下兩點
-
一個物件的行為取決於它的狀態,並且它必須在執行時刻根據狀態改變它的行為
-
一個操作中含有大量的分支語句,而且這些分支語句依賴於該物件的狀態。狀態通常為一個或多個列舉常量的表示
簡而言之,當遇到很多同級 if-else或者 switch的時候,可以使用狀態模式來進行簡化