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

简明 状态模式(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中....

有限状态机(FSM)的Java 演示的更多相关文章

  1. 有限状态机(FSM)的Java 学习FSM

    本文从简单的例子入手,逐步演变成非常复杂的程序. 在简明 状态模式(5.8)中,状态之间的变换由外界控制,或者说,多种状态是分割的.无关的.状态模式最有趣的地方正是讨论其状态的变迁. 1.引子 空调( ...

  2. cocos2d-x 游戏开发之有限状态机(FSM) (四)

    cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...

  3. Atitit. 有限状态机 fsm 状态模式

    Atitit. 有限状态机 fsm 状态模式 1. 有限状态机 1 2. "状态表"和"状态轮换表" 1 3. 有限状态机概念(状态(State)事件(Even ...

  4. 有限状态机FSM(自动售报机Verilog实现)

    有限状态机FSM(自动售报机Verilog实现) FSM 状态机就是一种能够描述具有逻辑顺序和时序顺序事件的方法. 状态机有两大类:Mealy型和Moore型. Moore型状态机的输出只与当前状态有 ...

  5. cocos2d-x 游戏开发之有限状态机(FSM) (三)

    cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...

  6. cocos2d-x 游戏开发之有限状态机(FSM) (一)

    cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...

  7. cocos2d-x 游戏开发之有限状态机(FSM) (二)

    cocos2d-x 游戏开发之有限状态机(FSM)  (二) 1 状态模式

  8. 有限状态机FSM

    有限状态机(Finite-state machine)又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.常用与:正则表达式引擎,编译器的词法和语法分析,游戏设计,网络 ...

  9. [原创][FPGA]有限状态机FSM学习笔记(一)

    1. 概述--何为有限状态机FSM? 有限状态机-Finite State Machine,简写为FSM,是表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用.通常 ...

随机推荐

  1. Eigen教程(8)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 原生缓存的接口:Map类 这篇将解释Eigen如何与原生raw C/C++ 数组混合 ...

  2. pandas 常用函数整理

    pandas常用函数整理,作为个人笔记. 仅标记函数大概用途做索引用,具体使用方式请参照pandas官方技术文档. 约定 from pandas import Series, DataFrame im ...

  3. 【Web安全】越权操作——横向越权与纵向越权

    参考:http://blog.csdn.net/github_39104978/article/details/78265433 看了上面的文章,对越权操作的概念还是比较模糊,不明确实际场景. 横向越 ...

  4. InstallShield卸载不彻底,残留大量dll文件

    今天发现安装包Client装c盘能正常删除,但是放d盘不能删除dll文件. 1.d盘安装程序包 2.检查脚本文件,卸载时通过messagebox打印INSTALLDIR和TARGERDIR,发现均指向 ...

  5. Android开发,在Fragment中,隐藏或关闭软键盘(虚拟键盘)的方法

    网上可以搜到各种方法,实际测试中,我的开发用机中,仅仅下面这个方法有效,记录一下. //隐藏虚拟键盘      public static void HideKeyboard(View v)      ...

  6. netable 禁用拖动

    nestable在点击的时候,有一个拖动的状态被触发,会导致你给nestable上加的链接都会无效. 只要在最外层的li里加入一个class为:dd-nodrag,就不会被触发了.然后你在子菜单中就可 ...

  7. SpringBoot 中 @RequestBody的正确使用方法

    SpringBoot 中 @RequestBody的正确使用方法 最近在接收一个要离职同事的工作,接手的项目是用SpringBoot搭建的,其中看到了这样的写法: @RequestMapping(&q ...

  8. kinect2的标定

    我用的是ubuntu14.04LTS,ROS 版本是indigo,kinect v2,我是用双系统装的ubuntu,关于怎么使用安装kinect2的安装以及使用的都在github上有着详细的说明 Ki ...

  9. 一个从MongoDB中导出给定日期范围内数据的shell脚本

    #!/bin/sh ver=`date "+%Y%m%d"` #d1, the beginning date, eg:2017-06-28 d1=$1 d1=`date -d $d ...

  10. Redis 学习笔记1

    配置文件: 根据配置文件打开服务器: redis-server redis.conf --port 6370 redis-cli -localhost -p 6370 动态设置/获取配置选项的值 CO ...