State模式

State模式

管理状态的就是State模式。下面一边看Java的程序逻辑一边介绍。管理状态的一般程序如下所示。


public boolean handleEvent(Event evt) {
    int& state;
    switch (evt.id) {
        case Event.COIN_INSERT:
            if (vendmachine.CoinInsert(state))
                state = COIN_INSERT;
            break;
        case Event.COIN_COMPLETE:
            if (vendmachine.CoinComp(state))
                state = COIN_ COMPLETE;
            break;
        }
    }

这个例子中,在发动机箱这个程序中有加速和减速这两个性能。状态有等待状态和运转状态。

状态模型如图2所示。这是非常简单的例子。
将其状态Idle、Running分别作为EngineState的子类。在该子类中,将各自的状态发生的行为作为方法进行描述。那么如果用Java编码的话会变成什么样呢。


    abstract class EngineState{
        void Up(EngineBox eb){}
            void Down(EngineBox eb){}
            void Error(EngineBox eb){}
            void ShowCurrentState(){}
    }
    class EngineRunning extends EngineState{
        PrintPanel pt = new PrintPanel();
            void Up(EngineBox eb){
                pt.Print("No More Up");
                eb.ChangeState(new EngineRunning());
            }
            void Down(EngineBox eb){
                pt.Print("Down to idle from running");
                eb.ChangeState(new EngineIdle());
            }
            void ShowCurrentState(){
                pt.Print("State:running");
            }
            }
    class EngineIdle extends EngineState{
            PrintPanel pt = new PrintPanel();
            void Up(EngineBox eb){
                pt.Print("Up to running from idle");
                eb.ChangeState(new EngineRunning());
            }
            void Down(EngineBox eb){
                pt.Print("No More Down");
                eb.ChangeState(new EngineIdle());
            }
            void ShowCurrentState(){
                pt.Print("State:idle");
            }
    }
    class EngineBox extends Object{
            EngineState state;
            EngineBox(){
                state = new EngineIdle();
            }
            void Up(){
                state.Up(this);
            }
            void Down(){
                state.Down(this);
            }
            void ChangeState(EngineState newState){
                state = newState;
                state.ShowCurrentState();
            }
    }
                    

关于编码的说明,EngineBox类的初期状态从图2的状态模型变成了Idle。这是通过state = new EngineIdle();进行的。
再看一下Up(),将EngineBox的对象-this (其自身)作为参数传送。因为这是从Up()中生成EngineBox的方法ChangeState()。
这时,为了改变状态new EngineRunning()从Idle变成Running状态。在EngineIdle、EngineRunning中,Up()、Down()对各自的行为进行编码。
因为OOP是解决难题的,大家也一边运行程序一边考虑逻辑。主要部分的生成简单地表示如下。


     EngineBox ebox;
     ebox = new EngineBox();
     ebox.Up();
                    

根据事件生成ebox.Down()和ebox.Up()。
改变式样,在运行中的状态中再试着增加一个low和high。因为State模式很灵活,只要稍微改变下子类就可以了。没有改变主要的EngineBox类。

类图如图4所示。

在不使用State模式的编码中加入新的状态的话,因为CASE语句中很多源代码都很零散,所以修改很花时间并且很容易出错。
相反,在State模式中创建要增加状态的子类后,只要改变该状态中行为的方法就可以了。不需要修改EngineBox类的编码。

<<修改后的Java编码>>
                                
    abstract class EngineState{
            void Up(EngineBox eb){}
            void Down(EngineBox eb){}
            void ShowCurrentState(){}
    }
    class EngineRunningLow extends EngineState{
            void Up(EngineBox eb){
                System.out.println("Up to running high from low");
                eb.ChangeState(new EngineRunningHigh());
            }
            void Down(EngineBox eb){
                System.out.println("Down to idle from running low");
                eb.ChangeState(new EngineIdle());
            }
            void ShowCurrentState(){
                System.out.println("State:running low");
            }
    }
    class EngineRunningHigh extends EngineState{
            void Up(EngineBox eb){
                System.out.println("No More Up");
                eb.ChangeState(new EngineRunningHigh());
            }
            void Down(EngineBox eb){
                System.out.println("Down to running low from high");
                eb.ChangeState(new EngineRunningLow());
            }
            void ShowCurrentState(){
              System.out.println("State:running high");
            }
    }
    class EngineIdle extends EngineState{
            void Up(EngineBox eb){
                System.out.println("Up to running low from idle");
                eb.ChangeState(new EngineRunningLow());
            }
            void Down(EngineBox eb){
                System.out.println("No More Down");
                eb.ChangeState(new EngineIdle());
            }
            void ShowCurrentState(){
                System.out.println("State:idle");
            }
    }
    class EngineBox extends Object{
            EngineState state;
            EngineBox(){
                state = new EngineIdle();
            }
            void Up(){
                state.Up(this);
            }
            void Down(){
                state.Down(this);
            }
            void ChangeState(EngineState newState){
                state = newState;
                state.ShowCurrentState();
            }
    }
                                   

这样的话,State模式要根据状态用相同的方法名改变内容时,就能起作用。不足之处是状态增多时,只有那部分必须要生成子类。