github上fork2.4k,star8.7k的这款状态机,原来长这样!
前言

▲原来的状态

▲改造后的状态(完整版)
StateMachineBuilder<ProcessStatusEnum, NodeTypeEnum, Context> builder = StateMachineBuilderFactory.create();
builder.internalTransition().within(ProcessStatusEnum.INIT).on(NodeTypeEnum.HEAD).when(alwaysTrue()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.INIT).to(END).on(NodeTypeEnum.HEAD).when(checkNextNodeIfEndComponet()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_YUNYIN).to(ProcessStatusEnum.SUBMIT_APPLY_PASS).on(NodeTypeEnum.SUBMIT_APPLY_COMPONET).when(checkIfPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_YUNYIN).to(ProcessStatusEnum.SUBMIT_APPLY_NOT_PASS).on(NodeTypeEnum.SUBMIT_APPLY_COMPONET).when(checkIfNotPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_FK).to(ProcessStatusEnum.FK_PASS).on(NodeTypeEnum.FK_COMPONET).when(checkIfPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_FK).to(ProcessStatusEnum.FK_AUDIT_NOT_PASS).on(NodeTypeEnum.FK_COMPONET).when(checkIfNotPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_FK).to(ProcessStatusEnum.FK_REFUSE).on(NodeTypeEnum.FK_COMPONET).when(checkIfRefuse()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_CW).to(ProcessStatusEnum.CW_PASS).on(NodeTypeEnum.CW_COMPONET).when(checkIfPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_CW).to(ProcessStatusEnum.CW_NOT_PASS).on(NodeTypeEnum.CW_COMPONET).when(checkIfNotPass()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_CW).to(ProcessStatusEnum.CW_REFUSE).on(NodeTypeEnum.CW_COMPONET).when(checkIfRefuse()).perform(doNextProcessStatus());
builder.externalTransition().from(ProcessStatusEnum.SOURCE_AUDIT_COMPLETE).to(ProcessStatusEnum.AUDIT_TERMINATE).on(NodeTypeEnum.AUDIT_TERMINATE).when(alwaysTrue()).perform(doNextProcessStatus());
builder.externalTransition().from(SOURCE_OP_CHANGE_LICENSE).to(ProcessStatusEnum.UPDATE_LICENSE_SUCCESS).on(NodeTypeEnum.CHANGE_LICENSE_COMPONET).when(checkIfPass()).perform(doNextProcessStatus());
builder.externalTransition().from(SOURCE_OP_CHANGE_LICENSE).to(ProcessStatusEnum.UPDATE_LICENSE_FAILURE).on(NodeTypeEnum.CHANGE_LICENSE_COMPONET).when(checkIfNotPass()).perform(doNextProcessStatus());
builder.externalTransition().from(SOURCE_END).to(END).on(NodeTypeEnum.TAIL).when(checkCurrentNodeIfEndComponet()).perform(doNextProcessStatus());
return builder.build("processStatusMachine");
github地址:https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine目前在github上:Fork:2.4k;Star:8.8k

快速开始
▲第一步:项目中引入Maven依赖
<dependency>
<groupId>com.alibaba.cola</groupId>
<artifactId>cola-component-statemachine</artifactId>
<version>4.3.1</version>
</dependency>
▲第二步:初始化状态机
@Configuration
public class StateMachineRegist {
private final String STATE_MACHINE_ID="stateMachineId";
/**
* 构建状态机实例
*/
@Bean
public StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine() {
StateMachineBuilder<ApplyStatusEnum, Event, LeaveContext> stateMachineBuilder = StateMachineBuilderFactory.create();
//员工请假触发事件
//源状态和目标状态一致,我们可以用内部流转表示
stateMachineBuilder.internalTransition().within(ApplyStatusEnum.LEAVE_SUBMIT).on(Event.EMPLOYEE_SUBMIT).perform(doAction());
//部门主管审批触发事件(依赖上一个源状态:LEAVE_SUBMIT)
stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEAVE_SUBMIT).to(ApplyStatusEnum.LEADE_AUDIT_PASS).on(Event.DIRECTLEADER_AUDIT).when(checkIfPass()).perform(doAction());
stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEAVE_SUBMIT).to(ApplyStatusEnum.LEADE_AUDIT_REFUSE).on(Event.DIRECTLEADER_AUDIT).when(checkIfNotPass()).perform(doAction());
//hr事件触发(依赖上一个源状态:LEADE_AUDIT_PASS)
stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEADE_AUDIT_PASS).to(ApplyStatusEnum.HR_PASS).on(Event.HR_AUDIT).when(checkIfPass()).perform(doAction());
stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEADE_AUDIT_PASS).to(ApplyStatusEnum.HR_REFUSE).on(Event.HR_AUDIT).when(checkIfNotPass()).perform(doAction());
return stateMachineBuilder.build(STATE_MACHINE_ID);
}
}

▲第三步:使用状态机状态机的使用分两步走:
第一步:获取状态机实例
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
第二步:向状态机触发一个fireEvent事件
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEAVE_SUBMIT, Event.EMPLOYEE_SUBMIT,context);
@DisplayName("员工提交请假申请单")
@Test
public void employSubmitRequest(){
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
LeaveContext context = new LeaveContext();
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEAVE_SUBMIT, Event.EMPLOYEE_SUBMIT,context);
Assert.assertEquals(ApplyStatusEnum.LEAVE_SUBMIT.getCode(),state.getCode());
}
@DisplayName("部门主管审批通过")
@Test
public void leaderAuditPass(){
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
LeaveContext context = new LeaveContext();
//主管审批通过
context.setIdea(0);
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEAVE_SUBMIT, Event.DIRECTLEADER_AUDIT,context);
Assert.assertEquals(ApplyStatusEnum.LEADE_AUDIT_PASS.getCode(),state.getCode());
}
@DisplayName("部门主管审批不通过")
@Test
public void leaderAuditNotPass(){
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
LeaveContext context = new LeaveContext();
//主管审批不通过
context.setIdea(1);
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEAVE_SUBMIT, Event.DIRECTLEADER_AUDIT,context);
Assert.assertEquals(ApplyStatusEnum.LEADE_AUDIT_REFUSE.getCode(),state.getCode());
}
@DisplayName("HR审批通过")
@Test
public void hrAuditPass(){
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
LeaveContext context = new LeaveContext();
//HR通过
context.setIdea(0);
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEADE_AUDIT_PASS, Event.HR_AUDIT,context);
Assert.assertEquals(ApplyStatusEnum.HR_PASS.getCode(),state.getCode());
}
@DisplayName("HR审批不通过")
@Test
public void hrAuditNotPass(){
StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine = StateMachineFactory.get("leaveStateMachineId");
LeaveContext context = new LeaveContext();
//HR审批不通过
context.setIdea(1);
ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEADE_AUDIT_PASS, Event.HR_AUDIT,context);
Assert.assertEquals(ApplyStatusEnum.HR_REFUSE.getCode(),state.getCode());
}
LEAVE_SUBMIT(1,"已申请"),
LEADE_AUDIT_PASS(2,"直属领导审批通过"),
LEADE_AUDIT_REFUSE(3,"直属领导审批失败"),
HR_PASS(4,"HR审批通过"),
HR_REFUSE(5,"HR审批拒绝");
架构设计
▲核心语义模型

//StateMachine
public class StateMachineImpl<S,E,C> implements StateMachine<S, E, C> {
private String machineId;
//一个状态机持有多个状态(from、to)
private final Map<S, State<S,E,C>> stateMap;
...
}
//State
public class StateImpl<S,E,C> implements State<S,E,C> {
protected final S stateId;
//同一个Event可以触发多个Transition
private Map<E, List<Transition<S, E,C>>> transitions = new HashMap<>();
...
}
//Transition
public class TransitionImpl<S,E,C> implements Transition<S,E,C> {
//源状态
private State<S, E, C> source;
//目标状态
private State<S, E, C> target;
//事件
private E event;
//条件
private Condition<C> condition;
//动作
private Action<S,E,C> action;
...
}
▲源码解析
@Override
public S fireEvent(S sourceStateId, E event, C ctx) {
isReady();
//根据sourceStateId找到符合条件的Transition
Transition<S, E, C> transition = routeTransition(sourceStateId, event, ctx);
if (transition == null) {
Debugger.debug("There is no Transition for " + event);
failCallback.onFail(sourceStateId, event, ctx);
return sourceStateId;
}
//找到transition后执行transit方法(最终执行Action后返回目标State)
return transition.transit(ctx, false).getId();
}
/**
* 路由Transition
* @param sourceStateId 源状态ID
* @param event 事件
* @param ctx 上下文参数
* @return
*/
private Transition<S, E, C> routeTransition(S sourceStateId, E event, C ctx) {
//根据源状态ID查找源状态实例
State sourceState = getState(sourceStateId);
//查找源状态实例下的流转列表
List<Transition<S, E, C>> transitions = sourceState.getEventTransitions(event);
if (transitions == null || transitions.size() == 0) {
return null;
}
Transition<S, E, C> transit = null;
for (Transition<S, E, C> transition : transitions) {
if (transition.getCondition() == null) {
transit = transition;
} else if (transition.getCondition().isSatisfied(ctx)) {
//一旦匹配when函数内的触发条件,返回transition
transit = transition;
break;
}
}
return transit;
}
@Override
public State<S, E, C> transit(C ctx, boolean checkCondition) {
Debugger.debug("Do transition: "+this);
this.verify();
//checkCondition为false或不指定when触发条件亦或匹配when触发条件;都将执行自定义的perform函数
if (!checkCondition || condition == null || condition.isSatisfied(ctx)) {
//如果自定义的perform函数有指定,将执行perform函数
if(action != null){
action.execute(source.getId(), target.getId(), event, ctx);
}
return target;
}
Debugger.debug("Condition is not satisfied, stay at the "+source+" state ");
return source;
}
总结
▲写到最后
关注我
如果这篇文章你看了对你有帮助或启发,麻烦点赞、关注一下作者。你的肯定是作者创作源源不断的动力。
公众号

里面不仅汇集了硬核的干货技术、还汇集了像左耳朵耗子、张朝阳总结的高效学习方法论、职场升迁窍门、软技能。希望能辅助你达到你想梦想之地!
公众号内回复关键字“电子书”下载pdf格式的电子书籍(JAVAEE、Spring、JVM、并发编程、Mysql、Linux、kafka、分布式等)、“开发手册”获取阿里开发手册2本、"面试"获取面试PDF资料。
github上fork2.4k,star8.7k的这款状态机,原来长这样!的更多相关文章
- python爬虫---->github上python的项目
这里面通过爬虫github上的一些start比较高的python项目来学习一下BeautifulSoup和pymysql的使用.我一直以为山是水的故事,云是风的故事,你是我的故事,可是却不知道,我是不 ...
- Github上值得关注的前端项目-转自好友trigkit4
http://microjs.com/# 该网站的资源都托管到了github,microjs.com是一个可以让你选择微型的js类库的网站,该网站里的js库都是压缩后不大于5KB的,非常实用 http ...
- Github上的沙雕项目,玩100遍都不够
这段时间大家在家自我隔离.居家办公憋坏了吧.为了打发这种无聊的生活,我决定拿出我在github上珍藏多年的沙雕项目,让大家在无聊的时候可以打发时间. Github作为互联网上最大的开源社区,一直备受程 ...
- 工作中经常用到github上优秀、实用、轻量级、无依赖的插件和库
原文收录在我的 GitHub博客 (https://github.com/jawil/blog) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博客,记录点滴. 按照格式推荐 ...
- GitHub上个最有意思的项目合集(技术清单系列)
没有1K以上的星星都不好意思推荐给大家!林子大了,啥项目都有,这里给大家搜罗了10个Github上有趣的项目.如果你就着辣椒食用本文,一定会激动的流下泪来...... 1.一行代码没有 | 18k s ...
- Github 上热门的 Spring Boot 项目实战推荐
最近经常被读者问到有没有 Spring Boot 实战项目可以学习,于是,我就去 Github 上找了 10 个我觉得还不错的实战项目.对于这些实战项目,有部分是比较适合 Spring Boot 刚入 ...
- GitHub 上的 12306 抢票神器,助力回家过年
又到周末了,不过本周末有些略微的特殊. 距离每年一次的全球最大规模的人类大迁徙活动已经只剩下一个多月了,各位在外工作一年的小伙伴大多数人又要和小编一样摩拳擦掌的对待史上最难抢的抢票活动. 然鹅,身为一 ...
- 工作中经常用到 github 上优秀、实用、轻量级、无依赖的插件和库
原文收录在 GitHub博客 ( https://github.com/jawil/blog ) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博客,记录点滴. 由于gith ...
- 清空Github上某个文件的历史版本
title: 清空Github上某个文件的历史版本 author: 青南 date: 2015-01-08 16:04:53 categories: [经验] tags: [Github,histor ...
- 手把手教从零开始在GitHub上使用Hexo搭建博客教程(四)-使用Travis自动部署Hexo(2)
前言 前面一篇文章介绍了Travis自动部署Hexo的常规使用教程,也是个人比较推荐的方法. 前文最后也提到了在Windows系统中可能会有一些小问题,为了在Windows系统中也可以实现使用Trav ...
随机推荐
- Mysql 安全加固经验总结
本文为博主原创,转载请注明出处: 目录 1.内网部署Mysql 2. 使用独立用户运行msyql 3.为不同业务创建不同的用户,并设置不同的密钥 4.指定mysql可访问用户ip和权限 5. 防sql ...
- 2022 CLion 中的Cygwin 配置(最全,最良心版)
目录 前景提要 一.windows 10 安装Cygwin 1.找到官网,进入官网,百度搜索或者点击下边链接. 2.找到如图位置,双击下载 3.下载完成后,找到下载的位置,双击exe文件. 4.进入欢 ...
- service服务使用CoreDNS提供的域名地址访问
普通的 Service:会生成 servicename.namespace.svc.cluster.local 的域名,会解析到 Service 对应的 ClusterIP 上,在 Pod 之间的调用 ...
- ProxySQL(2):初试读写分离
文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9278839.html 实现一个简单的读写分离 这里通过一个简单的示例实现ProxySQL的读写分离功能,算是 ...
- Elastic App Search 入门
官方文档地址:https://swiftype.com/documentation/app-search/getting-started Elastic App Search 架构图: 它的特点是帮助 ...
- 《Thinking In Java》作者:不要使用并发!
前言 今天纯粹就是带你们来读读书的~ 最近除了工作,特地买回了自己很喜欢的作者新发售的一本书<On Java>,作者是我的老朋友布鲁斯·埃克尔,在Java领域很有名,你可能没听过他的名字, ...
- nsis新插件:Aero.dll
可以使安装界面在 win7 Aero特效下非客户区透明并美化BrandingText定义的字串 下载:http://nsis.sourceforge.net/Aero_plug-in nsis交流群: ...
- TDengine的数据建模?库、表、超级表是什么?怎么用?
欢迎来到物联网的数据世界 在典型的物联网场景中,一般有多种不同类型的采集设备,采集多种不同的物理量,同一种采集设备类型,往往有多个设备分布在不同的地点,系统需对各种采集的数据汇总,进行计算和分析对于 ...
- 洛谷P1719 最大加权矩形 (DP/二维前缀和)
题目描述也没啥好说的,就是给你个你n*n的矩形(带权),求其中最大权值的子矩阵. 首先比较好想的就是二维前缀和,n<=120,所以可以用暴力. 1 #include<bits/stdc++ ...
- Spring_Boot项目集成Swagger填坑
事情是这样的: 最近疫情在家里闲的无聊 看了看Swagger-2 在练习的过程出现了错误 写个帖子 希望跟我有同样问题的朋友可以避雷. 下面进入正题: 编辑 我使用的swagger-2版本是2.9.4 ...