狀態模式的關鍵是區分事物內部的狀態,事物內部狀態的改變每每會帶來事物的行爲改變。設計模式
咱們來想象這樣一個場景:有一個電燈,電燈上面只有一個開關。當電燈開着的時候,此時 按下開關,電燈會切換到關閉狀態;再按一次開關,電燈又將被打開。同一個開關按鈕,在不一樣 的狀態下,表現出來的行爲是不同的bash
var Light = function(){
this.state = 'off'; // 給電燈設置初始狀態 off
this.button = null;// 電燈開關按鈕
};
Light.prototype.init = function(){
var button = document.createElement( 'button' ),
self = this;
button.innerHTML = '開關';
this.button = document.body.appendChild( button );
this.button.onclick = function(){
self.buttonWasPressed();
}
};
Light.prototype.buttonWasPressed = function(){
if ( this.state === 'off' ){
console.log( '開燈' );
this.state = 'on';
} else if ( this.state === 'on' ){
console.log( '關燈' );
this.state = 'off';
}
};
var light = new Light();
light.init();
複製代碼
假如如今電燈的狀態多了一種,第一次按下打開弱光,第二次按下打開強光,第三次纔是關閉電燈。以上的代碼就沒法知足這種電燈的狀況app
狀態模式的關鍵是把事物的 每種狀態都封裝成單獨的類,跟此種狀態有關的行爲都被封裝在這個類的內部,因此 button 被按下的的時候,只須要在上下文中,把這個請求委託給當前的狀態對象便可,該狀態對象會負責渲染它自身的行爲。以下圖所示post
/******************** 定義 3 個狀態類 ************************/
// OffLightState:
var OffLightState = function( light ){
this.light = light;
};
OffLightState.prototype.buttonWasPressed = function(){
console.log( '弱光' ); // offLightState 對應的行爲
this.light.setState( this.light.weakLightState );// 切換狀態到 weakLightState
};
// WeakLightState:
var WeakLightState = function( light ){
this.light = light;
};
WeakLightState.prototype.buttonWasPressed = function(){
console.log( '強光' ); // weakLightState 對應的行爲
this.light.setState( this.light.strongLightState ); //切換狀態到 strongLightState
};
// StrongLightState:
var StrongLightState = function( light ){
this.light = light;
};
StrongLightState.prototype.buttonWasPressed = function(){
console.log( '關燈' ); // strongLightState 對應的行爲
this.light.setState( this.light.offLightState ); // 切換狀態到 offLightState
};
/******************* 改寫 Light 類,使用狀態對象記錄當前的狀態 ******************/
var Light = function(){
this.offLightState = new OffLightState( this );
this.weakLightState = new WeakLightState( this );
this.strongLightState = new StrongLightState( this );
this.button = null;
};
/******************** 提供一個 方法來切換 light 對象的狀態 ************************/
Light.prototype.init = function(){
var button = document.createElement( 'button' ),
self = this;
this.button = document.body.appendChild( button );
this.button.innerHTML = '開關';
this.currState = this.offLightState;
this.button.onclick = function(){
self.currState.buttonWasPressed();
}
};
Light.prototype.setState = function( newState ){
this.currState = newState;
};
var light = new Light();
light.init();
複製代碼
執行結果跟以前的代碼一致,可是使用狀態模式的好處很明顯,它可使每 一種狀態和它對應的行爲之間的關係局部化,這些行爲被分散和封裝在各自對應的狀態類之中, 便於閱讀和管理代碼。 另外,狀態之間的切換都被分佈在狀態類內部,這使得咱們無需編寫過多的 if、else 條件 分支語言來控制狀態之間的轉換。this