處理物件的多種狀態及其相互轉換——狀態模式(五)

Liuwei-Sunny發表於2013-01-20

5 使用環境類實現狀態轉換

       在狀態模式中實現狀態轉換時,具體狀態類可通過呼叫環境類ContextsetState()方法進行狀態的轉換操作,也可以統一由環境類Context來實現狀態的轉換。此時,增加新的具體狀態類可能需要修改其他具體狀態類或者環境類的原始碼,否則系統無法轉換到新增狀態。但是對於客戶端來說,無須關心狀態類,可以為環境類設定預設的狀態類,而將狀態的轉換工作交給具體狀態類或環境類來完成,具體的轉換細節對於客戶端而言是透明的。

       在上面的“銀行賬戶狀態轉換”例項中,我們通過具體狀態類來實現狀態的轉換,在每一個具體狀態類中都包含一個stateCheck()方法,在該方法內部實現狀態的轉換,除此之外,我們還可以通過環境類來實現狀態轉換,環境類作為一個狀態管理器,統一實現各種狀態之間的轉換操作

       下面通過一個包含迴圈狀態的簡單例項來說明如何使用環境類實現狀態轉換:

       Sunny軟體公司某開發人員欲開發一個螢幕放大鏡工具,其具體功能描述如下:

       使用者單擊“放大鏡”按鈕之後螢幕將放大一倍,再點選一次“放大鏡”按鈕螢幕再放大一倍,第三次點選該按鈕後螢幕將還原到預設大小。

       可以考慮使用狀態模式來設計該螢幕放大鏡工具,我們定義三個螢幕狀態類NormalStateLargerStateLargestState來對應螢幕的三種狀態,分別是正常狀態、二倍放大狀態和四倍放大狀態,螢幕類Screen充當環境類,其結構如圖6所示:

6 螢幕放大鏡工具結構圖

       本例項核心程式碼如下所示:

//螢幕類
class Screen {
    //列舉所有的狀態,currentState表示當前狀態
	private State currentState, normalState, largerState, largestState;

	public Screen() {
    	this.normalState = new NormalState(); //建立正常狀態物件
    	this.largerState = new LargerState(); //建立二倍放大狀態物件
    	this.largestState = new LargestState(); //建立四倍放大狀態物件
    	this.currentState = normalState; //設定初始狀態
    	this.currentState.display();
	}
	
	public void setState(State state) {
		this.currentState = state;
	}
	
    //單擊事件處理方法,封轉了對狀態類中業務方法的呼叫和狀態的轉換
	public void onClick() {
    	if (this.currentState == normalState) {
    		this.setState(largerState);
    		this.currentState.display();
    	}
    	else if (this.currentState == largerState) {
    		this.setState(largestState);
    		this.currentState.display();
    	}
    	else if (this.currentState == largestState) {
    		this.setState(normalState);
    		this.currentState.display();
    	}
	}
}

//抽象狀態類
abstract class State {
	public abstract void display();
}

//正常狀態類
class NormalState extends State{
	public void display() {
		System.out.println("正常大小!");
	}
}

//二倍狀態類
class LargerState extends State{
	public void display() {
		System.out.println("二倍大小!");
	}
}

//四倍狀態類
class LargestState extends State{
	public void display() {
		System.out.println("四倍大小!");
	}
}

       在上述程式碼中,所有的狀態轉換操作都由環境類Screen來實現,此時,環境類充當了狀態管理器角色。如果需要增加新的狀態,例如“八倍狀態類”,需要修改環境類,這在一定程度上違背了“開閉原則”,但對其他狀態類沒有任何影響。

       編寫如下客戶端程式碼進行測試:

class Client {
	public static void main(String args[]) {
		Screen screen = new Screen();
		screen.onClick();
		screen.onClick();
		screen.onClick();
	}
}

       輸出結果如下:

正常大小!

二倍大小!

四倍大小!

正常大小!

【作者:劉偉 http://blog.csdn.net/lovelion

相關文章