github上fork2.4k,star8.7k的这款状态机,原来长这样!(状态机源码)

  本篇文章为你整理了github上fork2.4k,star8.7k的这款状态机,原来长这样!(状态机源码)的详细内容,包含有状态机软件 状态机源码 状态机 知乎 状态机代码生成器 github上fork2.4k,star8.7k的这款状态机,原来长这样!,希望能帮助你了解 github上fork2.4k,star8.7k的这款状态机,原来长这样!。

  上一篇文章《关于状态机的技术选型,最后一个真心好》我跟大家聊了一下关于”状态机“的话题。从众多技术选型中我也推荐了一款阿里开源的状态机—“cola-statemachine”。

  
 

  于是就有小伙伴私信我,自己项目也考虑引入这款状态机,但网上资料实在太少,能不能系统的介绍一下如何使用这款工具。

  
也是刚好前段时间因工作需要徒手写了一个简易版的工作流引擎(需要满足任意节点动态编排),里面涉及比较复杂的工作流状态流转,之前的if-else方案,实在搞的一团乱麻,自从引入了这款组件,一下子就解放了生产力。

  
上面还只是if-else实现版本中很小一部分代码,基本都是多个switch嵌套,最里面的switch又涉及多个if-else判断,可维护性和健壮性不言而喻。。

  

  


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

  
那接下来,废话不多说,我们先实战一把,先学会如何使用它。如果你想更加深入、全面的去了解组件的架构,可以看下架构设计部分章节。

  

  接下来,我以一个员工请假案例作为背景,手把手带大家演示一下如何使用此组件。

  
groupId com.alibaba.cola /groupId

   artifactId cola-component-statemachine /artifactId

   version 4.3.1 /version

   /dependency

 

 

  
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);

  }

 

 

  
我们在看内容左侧部分即State值,详细罗列了我们配置的状态(包括from和to)。这里我们知道总共有五种状态分别是:

  LEAVE_SUBMIT、LEADE_AUDIT_PASS、LEADE_AUDIT_REFUSE、HR_PASS、HR_REFUSE。

  
 

  这两个状态都是代表了状态机的源状态,里面包含了多个状态流转配置项即Transition部分。

  

  
Transition代表着状态的流转(分内部、外部流转),当客户端触发相应事件,状态机内部就能响应这个事件,一旦满足检查条件,最终就会返回目标状态。

  

  


StateMachine ApplyStatusEnum, Event, LeaveContext stateMachine = StateMachineFactory.get("leaveStateMachineId");

 

  


ApplyStatusEnum state=stateMachine.fireEvent(ApplyStatusEnum.LEAVE_SUBMIT, Event.EMPLOYEE_SUBMIT,context);

 

  
 

  fireEvent方法的第一个入参是源状态(对应状态机配置的from),第二个传递的是触发的事件(对应配置的on),第三个参数是一个自定义上下文参数(对应配置的context)。

  

  示例代码:

  
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());

  
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());

   }

 

 

  
我用cola-statemachine实现了整个生命周期的状态流转。完整代码我已开源在github上,感兴趣的小伙伴可以自取。

  
 

  一个状态机(StateMachine)包含多个状态(State)。一个状态(State)包含多个流转(Transition),一个Transition各包含一个Condition和Action。状态State分源状态(Source)和目标状态(Target)。源状态响应一个事件后,满足一定触发条件,经过流转,执行Action动作,最后返回Target状态。语义模型伪代码如下:

  


//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;

  }

 

  
//根据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();

   }

 

 

  
fireEvent方法内部首先会根据原状态ID去路由寻找具体的Transition,找到Transition后执行其transit方法,内部会执行perform函数,最终返回目标State。

  
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;

   }

 

 

  
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;

   }

 

 

  好了,文章即将进入尾声,让我们一起做个总结:

  

  前言部分,花了点时间简单给大家介绍了一下,在多状态属性场景中,状态机给我们带来的诸多好处。

  

  快速开始部分我比较细致的给大家介绍了代码层面如何正确使用该组件,也给出了一个基于"员工请假"案例的示例代码,用状态机实现内部审批状态流转。

  

  架构设计部分我先给大家介绍了一下该组件的核心语义模型,用类图来渲染。大家一看就能清楚知晓该状态机的内部构造及内部组件与组件之间的关系。源码部分,我从客户端触发的fireEvent方法开始,给大家讲解了一下它是如何从源状态开始,响应事件,匹配指定的Transition,执行具体的action动作,返回目标状态全过程。

  

  希望看完本文,对你能帮助你更加深入的了解这款优秀的开源状态机有所帮助,谢谢大家!

  

  
作为996的程序员,写这篇文章基本都是利用工作日下班时间和周六周日双休的时间才最终成稿,比较不易。

  

  
如果你看了文章之后但凡对你有所帮助或启发,真诚恳请帮忙关注一下作者,点赞、在看此文。你的肯定与赞美是我未来创作最强大的动力,我也将继续前行,创作出更加优秀好的作品回馈给大家,在此先谢谢大家了!

  如果这篇文章你看了对你有帮助或启发,麻烦点赞、关注一下作者。你的肯定是作者创作源源不断的动力。

  里面不仅汇集了硬核的干货技术、还汇集了像左耳朵耗子、张朝阳总结的高效学习方法论、职场升迁窍门、软技能。希望能辅助你达到你想梦想之地!

  公众号内回复关键字“电子书”下载pdf格式的电子书籍(JAVAEE、Spring、JVM、并发编程、Mysql、Linux、kafka、分布式等)、“开发手册”获取阿里开发手册2本、"面试"获取面试PDF资料。

  以上就是github上fork2.4k,star8.7k的这款状态机,原来长这样!(状态机源码)的详细内容,想要了解更多 github上fork2.4k,star8.7k的这款状态机,原来长这样!的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: