javascript狀態(tài)模式
狀態(tài)模式是解決某些需求場景的最好方法。狀態(tài)模式的關(guān)鍵是區(qū)分事物內(nèi)部的狀態(tài),事物內(nèi)部的狀態(tài)的改變往往會(huì)帶來事物的行為的改變
參考《javascript模式設(shè)計(jì)與開發(fā)實(shí)踐》第16章
我在前面寫了一個(gè)簡單的教程,為了說明react/redux中的狀態(tài)管理,《javascript模式設(shè)計(jì)與開發(fā)實(shí)踐》里面有這樣的模式。在下一步的重構(gòu)中,如果從簡單電燈的開關(guān)改為多級(jí)調(diào)光的電燈可以借鑒這樣的模式。在簡單的多個(gè)狀態(tài)之間切換的時(shí)候,這樣的模式是非常清晰的。
//兩個(gè)狀態(tài)之間的切換,使用if-else來切換,在有多個(gè)狀態(tài)的時(shí)候,這樣的切換就會(huì)嵌套很多的條件判斷語句,如果加入新的狀態(tài),修改代碼也比較困難
Light.prototype.buttonWasPressed = function(){
if ( this.state === 'off' ){
console.log( '開燈' );
this.state = 'on';
}else if ( this.state === 'on' ){
console.log( '關(guān)燈' );
this.state = 'off';
}
};
狀態(tài)模式的關(guān)鍵就是:把事物的每種狀態(tài)都封裝成單獨(dú)的類,跟此狀態(tài)相關(guān)的行為都被封裝在這個(gè)類的內(nèi)部。只要有交互行為,只需要在上下文中,把這個(gè)請(qǐng)求委托給當(dāng)前的狀態(tài)對(duì)象即可,該狀態(tài)對(duì)象會(huì)負(fù)責(zé)渲染它自身的行為。
- 封裝狀態(tài)
var OffLightState = function( light ){
this.light = light;
};
OffLightState.prototype.buttonWasPressed = function(){
console.log( '弱光' ); // offLightState 對(duì)應(yīng)的行為
this.light.setState( this.light.weakLightState ); // 切換狀態(tài)到weakLightState
};
// WeakLightState:
var WeakLightState = function( light ){
this.light = light;
};
WeakLightState.prototype.buttonWasPressed = function(){
console.log( '強(qiáng)光' ); // weakLightState 對(duì)應(yīng)的行為
this.light.setState( this.light.strongLightState ); // 切換狀態(tài)到strongLightState
};
// StrongLightState:
var StrongLightState = function( light ){
this.light = light;
};
StrongLightState.prototype.buttonWasPressed = function(){
console.log( '關(guān)燈' ); // strongLightState 對(duì)應(yīng)的行為
this.light.setState( this.light.offLightState ); // 切換狀態(tài)到offLightState
};
```
>在Light類中為每個(gè)狀態(tài)類都創(chuàng)建一個(gè)狀態(tài)對(duì)象,這樣一來就可以很明顯的看到電燈一共有多少個(gè)狀態(tài)
var Light = function(){
this.offLightState = new OffLightState( this );
this.weakLightState = new WeakLightState( this );
this.strongLightState = new StrongLightState( this );
this.button = null;
};
>在button按鈕被按下的時(shí)候,通過self.currState.buttonWasPressed()將請(qǐng)求委托為當(dāng)前的狀態(tài)去執(zhí)行。
Light.prototype.init = function(){
var button = document.createElement( 'button' ),
self = this;
this.button = document.body.appendChild( button );
this.button.innerHTML = '開關(guān)';
this.currState = this.offLightState; // 設(shè)置當(dāng)前狀態(tài)
this.button.onclick = function(){
self.currState.buttonWasPressed();
}
};
最后提供一個(gè)setState的方法,狀態(tài)對(duì)象通過這個(gè)方法來切換light對(duì)象的狀態(tài)。狀態(tài)對(duì)象的切換規(guī)律被定義在各個(gè)狀態(tài)類中。
Light.prototype.setState = function( newState ){
this.currState = newState; //設(shè)置下一個(gè)狀態(tài)
};
#####Javascript版本的狀態(tài)機(jī)
var Light = function(){
this.currState = FSM.off; // 設(shè)置當(dāng)前狀態(tài)
this.button = null;
};
Light.prototype.init = function(){
var button = document.createElement( 'button' ),
self = this;
button.innerHTML = '已關(guān)燈';
this.button = document.body.appendChild( button );
this.button.onclick = function(){
//初始化下就是調(diào)用FSM.off的方法設(shè)置內(nèi)部狀態(tài)self.currState.buttonWasPressed.call( self ); // 把請(qǐng)求委托給FSM 狀態(tài)機(jī)
}
};
var FSM = {
off: {
buttonWasPressed: function(){
console.log( '關(guān)燈' );
this.button.innerHTML = '下一次按我是開燈';
this.currState = FSM.on;
}
},
on: {
buttonWasPressed: function(){
console.log( '開燈' );
this.button.innerHTML = '下一次按我是關(guān)燈';
this.currState = FSM.off;
}
}
};
var light = new Light();
light.init();
具體的實(shí)例詳細(xì)看看書中的例子