狀態模式 State,狀態模式通過將複雜的條件判斷轉換為狀態模式,不同條件下的行為轉換為狀態對象,進而呈現出不同的行為,本文對狀態模式進行了簡單的介紹,並且對意圖,結構,角色,使用形式也進行了介紹,另外還給出了Java的狀態模式的實現。 ...
狀態模式 State
package state.example; public class A { void action() { System.out.println("A......."); } public static void main(String[] args) { A a = new A(); A b = new B(); A c = new C(); a.action(); b.action(); c.action(); } } class B extends A { @Override void action() { System.out.println("B......."); } class C extends A { @Override void action() { System.out.println("C......."); } }

意圖
允許一個對象在其內部狀態改變時改變他的行為。對象看起來似乎修改了他的類。 別名:狀態對象(Objects for States) 其實就是擁有狀態屬性,在不同的狀態下,呈現出不同的行為,並且可以靈活的切換狀態。 狀態:一個對象的行為取決於內部一個或者多個動態變化的屬性,這樣的屬性就叫做狀態。 有狀態的對象stateful:這樣的對象就叫做有狀態的對象。結構
不考慮Java語言的多態,如何達到“多態”的效果? 一種很自然的解決方案就是條件分支或者選擇語句,比如int state = 0; if(0 == state){ //... }else if(1 == state){ //... }else if(2 == state){ //... }else{ //... }int類型的變數state 就是“有狀態的對象”,state的具體的值就是“狀態”。 狀態的切換依賴state變數的賦值,不同行為的呈現藉助於條件分支。 顯然,如果業務邏輯複雜,將會有繁瑣複雜的分支判斷 更有甚者,如果有多個狀態共同決定行為,那麼豈不是多個狀態的複雜組合了? 而且如果新增加狀態,那麼就需要修改代碼,添加一個新的 else if(),擴展性不好,不符合開閉原則。 我們更希望的是能夠達到“多態”的那種調用效果,方法調用與具體的行為解耦。 調用者不需要關註具體的類型,在方法執行時,會具有真實類型的行為。 相當於變形為:
int state = 0; state.action();看起來,看起來好像,看起來好像action()方法封裝了類似下麵的判斷邏輯(只是看起來,其實他只有他自己狀態下的行為,不需要判斷)
if(0 == state){ //... }else if(1 == state){ //... }else if(2 == state){ //... }else{ //... }這不就是上面的多態示例麽,如果A表示抽象的狀態,B和C表示具體的某種狀態 如果所有使用狀態的地方,都使用靜態類型A,就可以根據實際類型達到多態的效果了。


代碼示例
抽象的State,定義狀態行為package state; public interface State { void handle(); }具體的狀態1
package state; public class ConcreateState1 implements State { @Override public void handle() { System.out.println("state 1 do sth"); } }具體的狀態2
package state; public class ConcreateState2 implements State { @Override public void handle() { System.out.println("state 2 do sth"); } }環境類,內部封裝了兩個狀態 state為當前狀態,初始時設置為狀態1了 通過changeState方法進行切換 action()方法為封裝調用state的handle方法
package state; public class Context { private final State STATE1 = new ConcreateState1(); private final State STATE2 = new ConcreateState2(); private State state = STATE1; public void action() { state.handle(); } public void changeState(int stateValue) { if (1 == stateValue) { state = STATE1; } else if (2 == stateValue) { state = STATE2; } } }

狀態的具體行為,狀態切換的時機等等都可以根據實際情況靈活處理,尤其是何時切換狀態,誰來負責切換狀態。 示例中,在環境類Context中創建了靜態的狀態對象,你可以根據實際情況動態的創建對象。 如果狀態頻繁變化,那麼事先創建所有狀態更合適,如果狀態設置後就很少變動,動態創建的形式或許更好。 狀態也可以持有環境類的引用,可以獲得更多的便利性。
另外的示例
如果僅僅是狀態的提取,簡化複雜的狀態判斷邏輯,藉助於State角色就可以完成 如果需要狀態的切換維護,或者要求狀態的順序等,總之對State的訪問需要增加更多的業務邏輯時,那麼就可以藉助於Context對State進行管理 通過Context封裝維護當前狀態,也就是Context提供代理方法,代理對當前狀態State的直接訪問 這樣就可以通過Context增加狀態切換,順序限制等更多的處理邏輯 比如下麵邏輯,假設狀態1,2,3,4,5,通過下麵的邏輯,就可以控制狀態的切換順序,當前狀態推導出下一個狀態void click(){
currentState.handle();
if(state == 1){
changeState(2);
}else if(state == 2){
changeState(3);
}
//.....
}
package state.order; public interface State { void handle(); }
package state.order; public class ConcreateState1 implements State { @Override public void handle() { System.out.println("state 1 do sth"); } }
package state.order; public class ConcreateState2 implements State { @Override public void handle() { System.out.println("state 2 do sth"); } }
package state.order; public class ConcreateState3 implements State { @Override public void handle() { System.out.println("state 3 do sth"); } }環境Context包括三種狀態,初始時當前狀態為狀態1 每次方法調用,都會按照順序切換狀態
package state.order; public class Context { private final State STATE1 = new ConcreateState1(); private final State STATE2 = new ConcreateState2(); private final State STATE3 = new ConcreateState3(); private State state = STATE1; public void action() { state.handle(); if (state == STATE1) { setState(STATE2); } else if (state == STATE2) { setState(STATE3); } else if (state == STATE3) { setState(STATE1); } } void setState(State state) { this.state = state; } }
