本文從簡單的樣例入手。逐步演變成很復雜的程序。
在簡明 狀態模式(5.8)中,狀態之間的變換由外界控制,或者說。多種狀態是切割的、無關的。狀態模式最有趣的地方正是討論其狀態的變遷。
1.引子
空調(air-condition)的遙控器有兩個button(很多其它的button
在后面的樣例中引入)。power/電源鍵和cool/制冷鍵。
空調的執行呈現3個狀態,停止/Off、僅送風/FanOnly、制冷/Cool。
起始狀態為Off。狀態變化圖例如以下所看到的。
這是簡化的有限狀態機(Finite State Machine、FSM或者Finite State Automata)圖形,使用了狀態圖的3個元素:①氣泡,表示狀態(state);②連接狀態的箭頭表示轉換(transition);③箭頭上的標記前者為事件(event)。

狀態的轉換,看圖說話。按power鍵,則Off→FanOnly、Cool→Off等;按cool。則Off→Off (沒有畫出來,喜歡全面一點就自己畫吧)。
對於這樣的簡單的狀態的轉換,yqj2065還是喜歡分支語句。
,簡潔明快。
例程 4-5 簡潔明快 package property.state.stateMachine; import static tool.Print.*;//pln /** * 空調Aircon。測試代碼的輸出:簡單的模型: * 遙控器有兩個button(很多其它的button在以下的樣例中引入)。power電源鍵和cool制冷鍵。 * 空調的執行呈現3個狀態。停止/Off、僅送風/FanOnly、制冷/Cool。 * 起始狀態為Off * @author (yqj2065) * @version 0.1 */ public class Aircon0{ // off,FanOnly。AC private int state=0;//起始狀態為Off public int getState(){return state;} //兩個Action public void power(){//按power鍵 if(state==0){//off state=1; pln("start Fan"); }else if(state==1){//FanOnly state=0; pln("stop Fan"); }else{ state=0; pln("stop Cool"); } } public void cool(){//按制冷鍵 if(state==0){//off pln("nothing"); }else if(state==1){//FanOnly state=2; pln("start Cool"); }else{ state=1; pln("stop Cool"); } } } package property.state.stateMachine; public class ACCtrl{ public static void test(){ Aircon0 ac = new Aircon0();//power() cool() System.out.println("Current State:" + ac.getState()); ac.cool(); ac.power(); ac.cool(); ac.cool(); ac.power(); ac.power(); } }
Current State:0
nothing
start Fan
start Cool
stop Cool
stop Fan
start Fan
在此基礎上。能夠花10分鍾練習一下,採用狀態模式改動上述代碼。
其結構例如以下:
例程 4 6 enum State
enum State0{
OFF{
@Override void power(){
}
@Override void power(){
}
},FANONLY{
},
COOL{ };
public abstract void power();
public abstract void cool();
}
(本來是應該將State1作為Aircon1的內部類的。放在外邊。power()等須要加入參數Aircon1,變為power(Aircon1 ac)).
如今,豐富有限狀態機的細節。增添④動作(action)。如事件(event)對應的動作和狀態的動作。

為此。在enum State1中。除了狀態模式 提取的接口外,加入了狀態機的各種動作/action methode
void entry(Aircon1 ac){pln("→"+ac.state.name());}
void exit(Aircon1 ac){p(ac.state.name()+"→ ");}
void startCool(){ p("start Cool"); }
void stopCool(){ p("stop Cool"); }
void startFan(){ p("start Fan"); }
void stopFan(){ p("stop Fan"); }
每一個power(Aircon1 ac)、cool(Aircon1 ac)的方法體結構都是:
this.exit(ac);
//假設有的話,事件(event)對應的動作,如stopFan();
ac.state =OFF; //下一個狀態
ac.state.entry(ac);
package property.state.stateMachine; import static tool.Print.*;//pln /** * 本來是應該將State1作為Aircon1的內部類的。如今放在外邊, * power()等須要變為power(Aircon1 ac) */ public enum State1{ OFF{ @Override void exit(Aircon1 ac){super.exit(ac);startFan();} @Override void power(Aircon1 ac){ this.exit(ac); ac.state =FANONLY; ac.state.entry(ac); } @Override void cool(Aircon1 ac){ pln("nothing"); } },FANONLY{ @Override void power(Aircon1 ac){ this.exit(ac); stopFan(); ac.state =OFF; ac.state.entry(ac); } @Override void cool(Aircon1 ac){ this.exit(ac); ac.state =COOL; ac.state.entry(ac); } }, COOL{ @Override void exit(Aircon1 ac){super.exit(ac);stopCool();} @Override void entry(Aircon1 ac){startCool();super.entry(ac);} @Override void power(Aircon1 ac){ this.exit(ac); stopFan(); ac.state =OFF; ac.state.entry(ac); } @Override void cool(Aircon1 ac){ this.exit(ac); ac.state =FANONLY; ac.state.entry(ac); } }; //狀態模式 提取的接口 abstract void power(Aircon1 ac); abstract void cool(Aircon1 ac); //狀態機的各種動作action methode void entry(Aircon1 ac){pln("→"+ac.state.name());} void exit(Aircon1 ac){p(ac.state.name()+"→ ");} void startCool(){ p("start Cool"); } void stopCool(){ p("stop Cool"); } void startFan(){ p("start Fan"); } void stopFan(){ p("stop Fan"); } }
空調Aircon1的改動版本號。
package property.state.stateMachine; import static tool.Print.*;//pln /** * 空調Aircon1。相應測試操作的輸出:“OFF→”表示離開OFF狀態,而“→FANONLY”...使用狀態模式重構Aircon0,使用enum State1編寫狀態類層次。
* @author (yqj2065) * @version 0.1 */ public class Aircon1{ State1 state= State1.OFF;//private改默認,刪除getState()。 //兩個Action public void power(){//按power鍵 state.power(this); } public void cool(){//按制冷鍵 state.cool(this); } /** * ACCtrl的代碼。 */ public static void test(){ Aircon1 ac = new Aircon1(); System.out.println("Current State:" + ac.state.name()); ac.cool(); ac.power(); ac.cool(); ac.cool(); ac.power(); ac.power(); ac.power(); } }
Current State:OFF
nothing
OFF→ start Fan→FANONLY
FANONLY→ start Cool→COOL
COOL→ stop Cool→FANONLY
FANONLY→ stop Fan→OFF
OFF→ start Fan→FANONLY
FANONLY→ stop Fan→OFF
2.分層狀態機
對於狀態較多的狀態機,通常將具有很多公共的特性的狀態合並到一起。比如FANONLY和COOL構成的 Running狀態。
狀態機中的hierarchical states,我們可以使用組合模式處理。
(還沒有單獨寫組合模式,
)。
可是,又不一定可以完美地使用組合模式。比如Running到Off,全部的Running的內部狀態在PoverEvent時都轉化到OFF,非常好;OFF到Running,不是全部Running的內部狀態都要調用其entry。在使用enum(不好搞類層次)時。使用責任鏈吧。
樓主繪圖中、考慮很多其它button中....

