今天主要介绍状态机生成工具SMC具体如何使用
SMC的用法综述
状态机是什么我就不赘述了,感兴趣的可以自行搜索文章了解一下 SMC的用法简单来说 就是用一个想成的jar包 + 一份sm文件(按到sm语法写的,规定了状态有哪些,状态怎么流转等等) ----> 用jar包执行 就会生成一个java类, 将java类放入项目中, 按照要求使用就实现了一个状态机.
大概步骤如下
1. 准备两个jar包
statemap.jar是用来作为本地依赖添加到依赖中
smc.jar用来将sm文件编译成java文件
2. idea添加SMC 的plugin
新建sm文件 test.sm 按照语法编写
%class TestSMC // 与该sm文件关联的接口类
%fsmclass TestStatusMachine // 生成后的java类名
%access public
%start TestStatus_Name::LOCKED // LOCKED是状态机的开始状态
%map TestStatus_Name %%
// 锁定状态
LOCKED
// Entry是别的状态跳转到当前状态时会执行的方法
// 这里就是别的状态跳转到LOCKED时 会执行LOCKED的Entry方法
Entry {
refreshTestStatus(); // 可以在状态流转前后自定义方法
}
{
TIME_OUT // 状态变化执行的操作
EXPIRED { // 可能变成的状态
}
}
EXPIRED 取消状态
Entry {
refreshTestStatus();
}
{
}
%%
3. 执行命令生成java类
利用 java -jar Smc.jar -java -d temp test.sm 生成编译结果 temp是编译后生成的java类存的位置 会得到一个TestStatusMachine的java类
4. 对项目中相关实体类进行改造
(1) 对于包含状态的实体类进行改造
新建sm文件中标记了的接口类TestSMC
该接口定义了 状态流转前后可能需要执行的操作
public interface TestSMC {
// 将状态机里的状态刷新到实体中
void refreshTestStatus();
}
包含状态的实体类继承该接口
正常状态肯定是被某个实体类包含的, 例如订单实体就有个字段是状态,通常是枚举,代表了订单所处的状态,那么就是订单实体类继承TestSMC接口
public class TestOrder implements TestSMC {
private Long orderId;
private TestStatus status;
// 状态机对象 就是第三步生成的java类
private TestStatusMachine testStatusMachine;
// 构造函数 新建该实体赋予实体一个初始状态
private TestOrder(TestStatus testStatus) { //TestStatus 是状态的枚举类
// 初始化状态机
testStatusMachine = new TestStatusMachine(this, TestStatus.getTestSMCStatus());
// 初始化订单状态
this.status = testStatus;
}
/**
* 接口方法的实现
* 将状态机当前的状态 刷新到status字段
* 由状态机自动完成更新
*/
@Override
public void refreshTestStatus () {
if (this.getTestStatusMachine() != null) {
String testStatusName = this.getTestStatusMachine().getState().getName().split("\\.")[1];
this.status = TestStatus.valueOf(testStatusName);
}
}
}
(2) 对于状态枚举类进行改造
public enum TestStatus {
LOCKED(0, "已锁量") {
@Override
public TestSMCState getTestSMCStatus() {
return TestStatus_Name.LOCKED;
}
},
EXPIRED(8, "已过期") {
@Override
public TestSMCState getTestSMCStatus() {
return TestStatus_Name.EXPIRED;
}
};
private int code;
private String desc;
OrderStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
// TestSMCState在自动生成的TestStatusMachine类里 每个枚举值都必须实现这个抽象方法
public abstract TestSMCState getTestSMCStatus();
}
具体的用法
// 新建一个初始为LOCKED的对象
TestOrder testOrder = new TestOrder(TestStatus.LOCKED);
// 为该对象发生状态变化
testOrder.getTestStatusMachine().TIME_OUT();
// 状态变化必须通过状态机进行 因为TestOrder没有为status设置set方法.
// 注意TIME_OUT()是在sm文件中规定的LOCKED状态唯一能进行的操作
通过这种用法status 只能通过sm文件已经规定好的行为 流转到指定的状态, 如果有人想不符合规范的通过代码修改状态,是无法进行的,保证了项目的规范性,当然这一切是通过相应的约定才行的,毕竟状态机只是方便状态的管理, 控制它合理的流转而已
如果需要新增状态 或者增加相应的状态流转 需要通过修改sm文件 重新生成java类, 并且相应的实体也要按规范修改
生成sm文件状态流转的图片
第一步:
java -jar Smc.jar -graph -glevel 1 test.sm
这个命令会生成一个test_sm.dot文件
第二步: 安装Graphviz后 可以将dot文件生成图片,类似下图
dot test_sm.dot -T png -o pic.png
官方文档(网上自行下载吧 好像上传不了)
SMC_Tutorial.pdf
SmcSrc_7_0_0.tgz