博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SCXML有限状态自动机
阅读量:5966 次
发布时间:2019-06-19

本文共 5990 字,大约阅读时间需要 19 分钟。

状态机简介

状态存储关于过去的信息,就是说:它反映从系统开始到现在时刻的输入变化。转移指示状态变更,并且用必须满足来确使转移发生的条件来描述它。动作是在给定时刻要进行的活动的描述。有多种类型的动作:

进入动作( entry action):在进入状态时进行 退出动作:在退出状态时进行 输入动作:依赖于当前状态和输入条件进行 转移动作:在进行特定转移时进行

    FSM(有限状态机)可以使用上面图 1 那样的(或状态转移图)来表示。此外可以使用多种类型的。下面展示最常见的表示:当前状态(B)和条件(Y)的组合指示出下一个状态(C)。完整的动作信息可以只使用脚注来增加。包括完整动作信息的 FSM 定义可以使用。

  • SCXML Parser
  • 核心 API,用于 SCXML 文档的解析模块,该 SCXML 文档中的各个元素解析组装成对应的 Java 对象实现。
  • DataModel
  • 核心 API,用于实现 SCXML 状态机中的数据模型定义,将 SCXML 文档中的 datamodel 元素对应的子元素封装成 Java 对象,供状态机引挚在后续操作中使用。
  • Context and Evaluators
  • 核心 API,用于实现对 SCXML 状态机中上下文环境的保存和更改,以及对 SCXML 文档中表达式语言(例如 <log expr=”${data.value}” />)的解析操作。
  • Executor
  • 引挚执行器的实例化模块,核心 API,通过此模块完成一个完整引挚执行器的组装和实例化,并提供引挚启动,停止服务器基础功能模块。
  • Triggering Event
  • 核心 API,SCXML 引挚中事件的定义实现和执行模块。此模块完成一个外部事件的封装,事件池的组织以及具体的事件作用流程控制。
  • Custom Actions
  • 高级 API,SCXML 状态机引挚的自定义事件支持。除了 SCXML 标准自带的 <var >、<assign> 和 <log> 等标准事件外,程序人员可以进行自定义事件的开发工作,例如系统平台的构件添加、构件删除操作等,需要程序人员的扩展开发工作。以下代码为 Custom Actions 的使用范例。
应用场景:
    
应用案例说明:
计时器的例子:
stopwatch state chart diagram
创建Maven工程:
commons-scxml
commons-scxml
0.9
commons-jexl
commons-jexl
1.1
xalan
xalan
2.6.0
创建状态机模型文件:stopwatch.xml
创建状态机:StopWatch.java
import org.apache.commons.scxml.SCXMLListener; import org.apache.commons.scxml.env.AbstractStateMachine; import org.apache.commons.scxml.model.ModelException; import org.apache.commons.scxml.model.State; import org.apache.commons.scxml.model.Transition; import org.apache.commons.scxml.model.TransitionTarget; import java.util.Timer; import java.util.TimerTask; public class StopWatch extends AbstractStateMachine {
/** * The events for the stop watch. */ public static final String EVENT_START = "watch.start", EVENT_STOP = "watch.stop", EVENT_SPLIT = "watch.split", EVENT_UNSPLIT = "watch.unsplit", EVENT_RESET = "watch.reset"; /** * The fragments of the elapsed time. */ private int hr, min, sec, fract; /** * The fragments of the display time. */ private int dhr, dmin, dsec, dfract; /** * The stopwatch "split" (display freeze). */ private boolean split; /** * The Timer to keep time. */ private Timer timer; /** * The display decorations. */ private static final String DELIM = ":", DOT = ".", EMPTY = "", ZERO = "0"; public StopWatch() throws ModelException {
super(StopWatch.class.getClassLoader().getResource("stopwatch.xml")); getEngine().addListener(getEngine().getStateMachine(), new EntryListener()); System.out.println(StopWatch.class.getClassLoader().getResource("stopwatch.xml")); } public void reset() {
hr = min = sec = fract = dhr = dmin = dsec = dfract = 0; split = false; } public void running() {
split = false; if (timer == null) {
timer = new Timer(true); timer.scheduleAtFixedRate(new TimerTask() {
@Override public void run() {
increment(); } }, 100, 100); } } public void paused() {
split = true; } public void stopped() {
timer.cancel(); timer = null; } public String getDisplay() {
String padhr = dhr > 9 ? EMPTY : ZERO; String padmin = dmin > 9 ? EMPTY : ZERO; String padsec = dsec > 9 ? EMPTY : ZERO; return new StringBuffer().append(padhr).append(dhr).append(DELIM). append(padmin).append(dmin).append(DELIM).append(padsec). append(dsec).append(DOT).append(dfract).toString(); } public String getCurrentState() {
return ((State)getEngine().getCurrentStatus().getStates().iterator().next()).getId(); } private void increment() {
if (fract < 9) {
fract++; } else {
fract = 0; if (sec < 59) {
sec++; } else {
sec = 0; if (min < 59) {
min++; } else {
min = 0; if (hr < 99) {
hr++; } else {
hr = 0; //wrap } } } } if (!split) {
dhr = hr; dmin = min; dsec = sec; dfract = fract; } } /** * A SCXMLListener that is only concerned about "onentry" * notifications. */ protected class EntryListener implements SCXMLListener {
public void onEntry(final TransitionTarget entered) {
System.out.println("Current State:"+entered.getId()); } public void onTransition(final TransitionTarget from, final TransitionTarget to, final Transition transition) {
// nothing to do } public void onExit(final TransitionTarget exited) {
// nothing to do } } }
测试代码:
public static void main(String[] args) throws ModelException {
StopWatch stopWatch = new StopWatch(); Scanner input=new Scanner(System.in); System.out.println("event: watch.start watch.stop watch.reset watch.split watch.unsplit"); while(true){
String event=input.nextLine(); if(event.trim()!=null&&!event.trim().equals("")){
if(event.equals("exit")) break; else{
stopWatch.fireEvent(event); System.out.println(stopWatch.getCurrentState()); System.out.print(stopWatch.getDisplay()); } } } }
每一个状态下会调用对应状态的方法来处理具体的业务处理逻辑。这样就可以实现一个简单的处理机。
Q&A:
关于序列化:2.0版本中可以通过将SCXML中attach的SCInstance实例的序列化来完成,恢复后通过deattach来恢复。
状态恢复:可以通过引入一个新的状态reset状态
reference:

转载地址:http://ajxax.baihongyu.com/

你可能感兴趣的文章
HashMap内部是如何实现的(转)
查看>>
交互设计[3]--点石成金
查看>>
java实现双向循环链表
查看>>
如何使用缓存提高程序性能
查看>>
【trie树】HDU4825 Xor Sum
查看>>
SCCM TP4部署Office2013
查看>>
Linux系统启动过程,grub重装。
查看>>
使用Putty密钥认证机制远程登录Linux
查看>>
一不小心,老司机又翻车了
查看>>
理解思科IPS系统的traffic flow notifications
查看>>
【博客话题】技术人生之三界修炼
查看>>
Ext JS 6开发实例(三) :主界面设计
查看>>
Hyper-V 3中虚拟机CPU竞争机制
查看>>
【原创】Oracle RAC原理和安装
查看>>
东哥读书小记 之 《MacTalk人生元编程》
查看>>
《随机出题软件》&《随机分队软件》源码(Windows API)
查看>>
python 文件及文件夹操作
查看>>
Android自定义ListView的Item无法响应OnItemClick的解决办法
查看>>
Building Apps for Windows Phone 8.1教程下载地址整理
查看>>
移动Web—CSS为Retina屏幕替换更高质量的图片
查看>>