赞
踩
smc官网地址: smc官方网站.
SMC是用java开发的一个状态机软件代码生成工具,SMC支持多种开发语言:C、JavaScript、Python、C++、Lua、Ruby、C#、Objective-C、Scala、Groovy、Perl、TCL、Java、PHP、VB.NET等,而我们需要做的就是完成一个.sm的脚本和拥有这些状态的主体类。
利用有限状态机来控制对象的行为,其原理就是利用多态,常常我们自己写代码,需要很大篇幅,万一需要再加一个或者几个状态,自己维护时就会很麻烦,SMC这个工具可以帮助我们解决这个问题。
SMC可以通过一个配置文件,生成有限状态机所需的所有状态类以及状态机类,同时还包括了所有的状态间的转换逻辑。
我们这里以java语言为例来进行说明。
使用这个工具之前我们需要jdk环境,最新版的SMC支持jdk1.7,之前版本的SMC支持jdk1.6,要想中间没有问题,一定要将电脑上的jdk版本与SMC的jdk版本对应起来。
smc下载地址: http://sourceforge.net/projects/smc/files/.
%class 状态机所作用的类
%package 类所在的包
%access 生成类的可访问级别
%start 指定状态机的开始状态
%map 状态机的名字
%%...%%:这一对%%中间定义了各个状态类以及状态的各种行为。格式说明如下:
注意:sm文件名称需要与.sm文件中指定的%class 类名称 相同
Start --状态1(名称可自定义) { DoStart --Do状态名:执行状态1 State2–执行完状态1之后,跳转到该状态(状态2) {method1();}–执行状态1时,需要实现的功能 } State2-状态2 { DoState2 [ctxt.isSuccessState2()== true] – ctxt:上下文,实体类CoreSchMatch 中isSuccessState2()函数返回值为true时,执行该功能 State3 { notifyClientState2Ok(); } DoState2 [ctxt.isSuccessState2()==== false] – ctxt:上下文,实体类CoreSchMatch 中isSuccessState2()函数返回值为false时,执行该功能 State2Fail{notifyClientState2Fail();} } State3 { DoState3 nil{method3();releaseStm();}–表示清空资源;nli-结束状态 } State2Fail { DoState2Fail nil{releaseStm();}–表示清空资源;nli-结束状态 Default -- 默认状态转换:被放置在一个状态中,用于备份所有转换。 { nil{ process();} } } Default –默认状态,如果状态机接收到未在该状态机中定义的转换时,定义该状态下的动作或转换 { DoStart nil {} DoState2 nil {} DoState3 nil {} DoState2Fail nil {} }
1、创建java工程;
2、引入jar包:Smc.jar
3、创建:SchMatchState.sm文件
下面设计这样一个简单状态机,程序初始化时,进入"start"初始状态;当在”"start"初始状态收到信号时,进入”busy“状态;当在"busy"状态收到一个"special"的信号时,进入"idle"状态,当在"busy"状态收到一个"exception"的信号时,进入"stop"退出状态。
实现这个状态机的.sm脚本我们将它命名为SchMatchState.sm,
具体的脚本如下所示:
%{ %} %class SchMatchState %package com.math.sch %start SchMatchStateMap::Start %map SchMatchStateMap %% Start { DoStart Busy{state2Busy();} } Busy { DoBusy [ctxt.isSpecialState() == true] Idle{idleProcess();} DoBusy [ctxt.isSpecialState() == false] Stop{stopProcess();} } Idle{ DoIdle nil {release();} } Stop{ DoStop nil {release();} } Default { DoStart nil {} DoBusy nil {} DoIdle nil {} DoStop nil {} } %%
执行.sm文件,生成对应的类和方法,有两种方法:
1、通过命令行执行生成;
2、通过ant自动化编译工具生成;
1、命令行内容:
java -jar Smc.jar -java -g -d ./ 需要处理的状态机.sm文件名
示例:
java -jar Smc.jar -java -g -d ./ SchMatchState.sm
2、执行命令:
(1)Window+R,打开cmd命令行窗口;
(2)在命令行中进入smc.jar包的位置:
(3)执行命令:
注意:sm文件名称需要与.sm文件中指定的%class 类名称 相同,我这边因为名称不相同导致生成异常:
执行过程:
3、执行之后,程序会自动创建SchMatchStateContext类,类中定义状态机的全过程。
4、 SchMatchState类中会自动创建状态机中定义的所有功能函数,根据实际需要实现对应的功能即可。
如果没有生成SchMatchState类,可在SchMatchStateContext类中根据提示,依次生成对应的类和函数,并实现对应的函数功能。
5、 在SchMatchState类中实现startCoreSchMatch()函数,用于状态机启动 --> 执行所有的动作函数:
public void startCoreSchMatch(){
fsm.enterStartState();
fsm.DoStart();
fsm.DoBusy();
fsm.DoIdle();
fsm.DoStop();
}
Apache Ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。在实际软件开发中,有很多地方可以用到ant。
ant的相关介绍和下载可参考链接: Apache Ant的基础使用教程.
本文案例的资源链接:SMC - 状态机 - Java工程实现示例.
package com.math.sch; public class SchMatchState { private SchMatchStateContext fsm; private String currentState = "start"; public static void main(String[] args) { new SchMatchState().start(); } public void start(){ System.out.println("状态机开始: "); this.fsm = new SchMatchStateContext(this); startCoreSchMatch(); } public void startCoreSchMatch(){ fsm.enterStartState(); fsm.DoStart(); fsm.DoBusy(); fsm.DoIdle(); fsm.DoStop(); } public void state2Busy() { this.currentState = "busy"; System.out.println("当前状态:"+currentState+" -> 转换状态至:busy"); } public boolean isSpecialState() { if("busy".equals(currentState)){ this.currentState = "Special"; return true; } return false; } public void idleProcess() { System.out.println("当前状态:"+currentState+" -> 转换状态至:idle"); this.currentState = "stop"; } public void stopProcess() { this.currentState = "stop"; System.out.println("当前状态:"+currentState); } public void release() { this.currentState = "start"; System.out.println("状态机结束并清空"); } }
执行结果输出情况:
总结:FSM是一种固定的范式,因此采用工具帮我们实现可以减少犯错误的机会。输入的文件就是:实体.sm。我们把重点放在业务逻辑上,所以与状态有关的代码smc都帮我们生成好了。
/* * ex: set ro: * DO NOT EDIT. * generated by smc (http://smc.sourceforge.net/) * from file : SchMatchState.sm */ package com.math.sch; import java.io.PrintStream; public class SchMatchStateContext extends statemap.FSMContext { //--------------------------------------------------------------- // Member methods. // public SchMatchStateContext(SchMatchState owner) { super (SchMatchStateMap.Start); _owner = owner; } public SchMatchStateContext(SchMatchState owner, SchMatchStateState initState) { super (initState); _owner = owner; } public void enterStartState() { getState().Entry(this); return; } public void DoBusy() { _transition = "DoBusy"; getState().DoBusy(this); _transition = ""; return; } public void DoIdle() { _transition = "DoIdle"; getState().DoIdle(this); _transition = ""; return; } public void DoStart() { _transition = "DoStart"; getState().DoStart(this); _transition = ""; return; } public void DoStop() { _transition = "DoStop"; getState().DoStop(this); _transition = ""; return; } public SchMatchStateState getState() throws statemap.StateUndefinedException { if (_state == null) { throw( new statemap.StateUndefinedException()); } return ((SchMatchStateState) _state); } protected SchMatchState getOwner() { return (_owner); } public void setOwner(SchMatchState owner) { if (owner == null) { throw ( new NullPointerException( "null owner")); } else { _owner = owner; } return; } //--------------------------------------------------------------- // Member data. // transient private SchMatchState _owner; //--------------------------------------------------------------- // Inner classes. // public static abstract class SchMatchStateState extends statemap.State { //----------------------------------------------------------- // Member methods. // protected SchMatchStateState(String name, int id) { super (name, id); } protected void Entry(SchMatchStateContext context) {} protected void Exit(SchMatchStateContext context) {} protected void DoBusy(SchMatchStateContext context) { Default(context); } protected void DoIdle(SchMatchStateContext context) { Default(context); } protected void DoStart(SchMatchStateContext context) { Default(context); } protected void DoStop(SchMatchStateContext context) { Default(context); } protected void Default(SchMatchStateContext context) { if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println( "TRANSITION : Default"); } throw ( new statemap.TransitionUndefinedException( "State: " + context.getState().getName() + ", Transition: " + context.getTransition())); } //----------------------------------------------------------- // Member data. // } /* package */ static abstract class SchMatchStateMap { //----------------------------------------------------------- // Member methods. // //----------------------------------------------------------- // Member data. // //------------------------------------------------------- // Constants. // public static final SchMatchStateMap_Default.SchMatchStateMap_Start Start = new SchMatchStateMap_Default.SchMatchStateMap_Start("SchMatchStateMap.Start", 0); public static final SchMatchStateMap_Default.SchMatchStateMap_Busy Busy = new SchMatchStateMap_Default.SchMatchStateMap_Busy("SchMatchStateMap.Busy", 1); public static final SchMatchStateMap_Default.SchMatchStateMap_Idle Idle = new SchMatchStateMap_Default.SchMatchStateMap_Idle("SchMatchStateMap.Idle", 2); public static final SchMatchStateMap_Default.SchMatchStateMap_Stop Stop = new SchMatchStateMap_Default.SchMatchStateMap_Stop("SchMatchStateMap.Stop", 3); private static final SchMatchStateMap_Default Default = new SchMatchStateMap_Default("SchMatchStateMap.Default", -1); } protected static class SchMatchStateMap_Default extends SchMatchStateState { //----------------------------------------------------------- // Member methods. // protected SchMatchStateMap_Default(String name, int id) { super (name, id); } protected void DoStart(SchMatchStateContext context) { if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Default.DoStart()"); } return; } protected void DoBusy(SchMatchStateContext context) { if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Default.DoBusy()"); } return; } protected void DoIdle(SchMatchStateContext context) { if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Default.DoIdle()"); } return; } protected void DoStop(SchMatchStateContext context) { if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Default.DoStop()"); } return; } //----------------------------------------------------------- // Inner classse. // private static final class SchMatchStateMap_Start extends SchMatchStateMap_Default { //------------------------------------------------------- // Member methods. // private SchMatchStateMap_Start(String name, int id) { super (name, id); } protected void DoStart(SchMatchStateContext context) { SchMatchState ctxt = context.getOwner(); if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Start.DoStart()"); } (context.getState()).Exit(context); context.clearState(); try { ctxt.state2Busy(); } finally { context.setState(SchMatchStateMap.Busy); (context.getState()).Entry(context); } return; } //------------------------------------------------------- // Member data. // } private static final class SchMatchStateMap_Busy extends SchMatchStateMap_Default { //------------------------------------------------------- // Member methods. // private SchMatchStateMap_Busy(String name, int id) { super (name, id); } protected void DoBusy(SchMatchStateContext context) { SchMatchState ctxt = context.getOwner(); if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Busy.DoBusy()"); } if (ctxt.isSpecialState() == true) { (context.getState()).Exit(context); context.clearState(); try { ctxt.idleProcess(); } finally { context.setState(SchMatchStateMap.Idle); (context.getState()).Entry(context); } } else if (ctxt.isSpecialState() == false) { (context.getState()).Exit(context); context.clearState(); try { ctxt.stopProcess(); } finally { context.setState(SchMatchStateMap.Stop); (context.getState()).Entry(context); } } else { super.DoBusy(context); } return; } //------------------------------------------------------- // Member data. // } private static final class SchMatchStateMap_Idle extends SchMatchStateMap_Default { //------------------------------------------------------- // Member methods. // private SchMatchStateMap_Idle(String name, int id) { super (name, id); } protected void DoIdle(SchMatchStateContext context) { SchMatchState ctxt = context.getOwner(); if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Idle.DoIdle()"); } SchMatchStateState endState = context.getState(); context.clearState(); try { ctxt.release(); } finally { context.setState(endState); } return; } //------------------------------------------------------- // Member data. // } private static final class SchMatchStateMap_Stop extends SchMatchStateMap_Default { //------------------------------------------------------- // Member methods. // private SchMatchStateMap_Stop(String name, int id) { super (name, id); } protected void DoStop(SchMatchStateContext context) { SchMatchState ctxt = context.getOwner(); if (context.getDebugFlag() == true) { PrintStream str = context.getDebugStream(); str.println("TRANSITION : SchMatchStateMap.Stop.DoStop()"); } SchMatchStateState endState = context.getState(); context.clearState(); try { ctxt.release(); } finally { context.setState(endState); } return; } //------------------------------------------------------- // Member data. // } //----------------------------------------------------------- // Member data. // } } /* * Local variables: * buffer-read-only: t * End: */
生成sm工作流程图,可以通过图形直观看到当前.sm文件定义的状态及转移过程情况。
详情链接:Graphviz - 生成smc 的.sm文件对应的工作流程图.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。