zoukankan      html  css  js  c++  java
  • 有限状态机(FSM)的Java 演示

    本文从简单的样例入手。逐步演变成很复杂的程序。

    简明 状态模式(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分钟练习一下,採用状态模式改动上述代码。

    我们使用enum编写状态类层次

    其结构例如以下:

    例程 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。

    使用状态模式重构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(); } }

    相应測试操作的输出:“OFF→”表示离开OFF状态,而“→FANONLY”...

    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中....


  • 相关阅读:
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    Java实现 LeetCode 792 自定义字符串排序(暴力)
    asp.net session对象的持久化
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 791 自定义字符串排序(桶排序)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    Java实现 LeetCode 790 多米诺和托米诺平铺(递推)
    小白也能看懂的约瑟夫环问题
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6791610.html
Copyright © 2011-2022 走看看