如何用狀態模式優化你的 JavaScript 代碼
狀態模式是一個有趣的模式,它可能是解決一些需求場景的最佳方式。雖然狀態模式不是一種易于學習的模式(它通常會導致代碼量增加),但一旦您了解了狀態模式的本質,您將在未來感謝它無與倫比的好處。
網上很多文章在解釋狀態模式時,都過于理論化,難以理解。這里我嘗試用一個實際案例用通俗易懂的方式來解釋。
01、打開/關閉燈?
讓我們想象一個場景,其中有一盞燈只有一個開關。
- 燈亮時按下開關,燈將關閉。
- 再按一下開關,燈就亮了。
我們可以發現一個特點:同一個開關按鈕在不同的狀態下會有不同的行為。
現在讓我們編寫一段代碼來模擬燈光,并打開和關閉燈光,如何編寫代碼?
一個簡單的實現:
class Light{
constructor() {
this.state = 'off'
}
clickButton() {
if (this.state === 'off') {
console.log('turn on the light')
this.state = 'on'
} else if (this.state === 'on') {
console.log('turn off the light')
this.state = 'off'
}
}
}
用法:
02、多態
在上面的場景中,燈只有兩種狀態,所以代碼寫起來比較簡單。
但我們需要知道,在現實生活中,很多物體都有兩種以上的狀態,一旦一個對象有更多的狀態,它就會更麻煩。
例如,有些手電筒具有三種狀態:
- 關閉狀態
- 弱光狀態
- 強光狀態?
第一次按下開關打開弱光,第二次按下打開強光,第三次按下關閉燈。
現在讓我們模擬這樣的行為,我們應該如何寫代碼?
03、正常解決方案
正常的解決方案是擴展前面的代碼,在clickButton方法中進行一些額外的狀態判斷和狀態切換。
class Light{
constructor() {
this.state = 'off'
}
clickButton() {
if (this.state === 'off') {
console.log('Turn on the low light')
this.state = 'lowLight'
} else if (this.state === 'lowLight') {
console.log('Switch to the strong light')
this.state = 'strongLight'
} else if (this.state === 'strongLight') {
console.log('turn off the light')
this.state = 'off'
}
}
}
雖然這樣的代碼可以滿足要求,但它有很多缺點。
- 如果以后需要添加或者修改Light的狀態,那么就需要不斷的修改clickButton方法,使得clickButton不穩定,不符合開閉原則。
- 同時,所有與狀態相關的行為都放在了clickButton方法中,不符合單一職責原則。如果以后加入新的狀態,比如superStrongLight,clickButton方法會越來越臃腫。
- 最后,狀態之間的切換完全依賴于在 clickButton 方法中堆疊 if 和 else 語句。添加或修改狀態可能需要更改多個操作,這使得該方法更難以閱讀和維護。
04、分析
讓我們回想一下,我們的代碼使用 Light 作為一個單獨的對象,然后它具有三種狀態。然后我們需要讓它在不同的狀態之間切換,我們將不同的狀態視為光的內部屬性。
但實際上,我們可以打破慣性思維,將每一個狀態都視為一個獨立的存在,封裝成一個單獨的類。
比如這里的燈有三種狀態:
- 低光狀態
- 強光狀態
- 關閉狀態
不同狀態的燈有自己的行為特征。
LowLightState 的clickButton 方法將狀態切換為StrongLightState,StrongLightState 的clickButton 將狀態切換為OffState。
而我們的Light只需要關注它處于什么狀態,不需要處理狀態切換,狀態切換由每個狀態自己處理。
這是完整的代碼:
class OffLightState{
constructor(light) {
this.light = light
}
clickButton() {
console.log('Turn on the low light')
this.light.setState(this.light.lowLightState)
}
}
class LowLightState {
constructor(light) {
this.light = light
}
clickButton() {
console.log('Switch to the strong light')
this.light.setState(this.light.strongLightState)
}
}
class StrongLightState {
constructor(light) {
this.light = light
}
clickButton() {
console.log('turn off the light')
this.light.setState(this.light.offLightState)
}
}
class Light{
constructor() {
this.offLightState = new OffLightState(this);
this.lowLightState = new LowLightState(this);
this.strongLightState = new StrongLightState(this);
this.currentState = this.offLightState
}
setState(newState) {
this.currentState = newState
}
clickButton() {
this.currentState.clickButton()
}
}
let light = new Light()
light.clickButton()
light.clickButton()
light.clickButton()
圖中解釋:
這樣的代碼可以解決前面提到的問題:
輕物體更簡單。它只需要調用this.currentState.clickButton(),狀態切換可以由狀態對象自己處理。
如果將來有新的狀態,我們只需要創建一個新的狀態類,然后修改其相鄰的狀態類,而不需要對現有代碼進行大量修改。
這種編寫代碼的技術就是狀態模式。
05、狀態模式
狀態模式的正式定義:
狀態模式是一種行為軟件設計模式,它允許對象在其內部狀態發生變化時改變其行為。這種模式接近于有限狀態機的概念。狀態模式可以解釋為策略模式,它能夠通過調用模式接口中定義的方法來切換策略。?
簡單來說,如果你的對象有多個狀態,并且不同狀態的對象表現不同,那么你可以考慮使用狀態模式。
狀態模式有時會增加代碼行數,但代碼的質量并不取決于代碼行數。使用狀態模式通??梢允鼓膶ο蟮倪壿嫺雍啙崱?/p>
總結
以上就是我今天與你分享的關于在JavaScript中使用狀態模式簡化對象的全部內容,希望這些內容對你有幫助,如果你覺得我今天的內容有用的話,請將它分享給你身邊的朋友,也許能夠幫助到他。