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

简明 状态模式(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. C#学习笔记(13)——传统方法读取XML

    说明(2017-7-12 16:32:47): 1. LINQ的方法虽然很简单,但是有点不好理解,sql的写法总感觉很诡异,而且LINQ的本质也是用的传统方法,所以还是采用老办法吧! 2. 注释里的代 ...

  2. C# using关键字 --转

    其实对于.NET的学习者一开始都接触using这个关键字了,可能大家没有怎么在意,包括我本人也是的,直到今天有人问我using的作用时,才引起了我的注意.       概况来说可以分为两种:第一种,就 ...

  3. java框架篇---struts实现拦截器

    Struts2的拦截器和Servlet过滤器类似.在执行Action的execute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept ...

  4. CSS超过指定的宽度加省略号

    /*table-layout:fixed 会使表格均等分*/ #TreeView1 table { width:290px; table-layout: fixed; } #TreeView1 td: ...

  5. 【应用笔记】【AN005】Qt开发环境下基于RS485的4-20mA电流采集

    简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍在Qt开发环境下基于RS485实现4-20mA电流采集,实现WINDOWS平台对数据的采集.分析及显示. 系统组成 ...

  6. ubuntu 安装 sshd

    ubuntu 上可以安装 SSHD 服务,方便远程操作. sudo apt-get update sudo apt-get install openssh-server sudo /etc/init. ...

  7. android 中遇到 imageView getWidth 始终为0 时 ,设置 setImageBitmap 的方法

    先说说我的遇到的问题: 1. 我在activity里写一个 fragment 2.这个fragment里有个 imageView ,用于显示图片. 我使用 asyncTask获得图片,并准备在这个im ...

  8. js 添加天数

    //日期加上天数得到新的日期 //dateTemp 需要参加计算的日期,days要添加的天数,返回新的日期,日期格式:YYYY-MM-DD function getNewDay(dateTemp, d ...

  9. linq操作符:连接操作符

    linq中的连接操作符主要包括Join()和GroupJoin()两个. 一.Join()操作符 Join()操作符非常类似于T-SQL中的inner join,它将两个数据源进行连接,根据两个数据源 ...

  10. Kafka设计解析(二):Kafka High Availability (上)

    转自:http://www.infoq.com/cn/articles/kafka-analysis-part-2/ Kafka在0.8以前的版本中,并不提供High Availablity机制,一旦 ...