首页 > 其他分享 >Squirrel状态机-从原理探究到最佳实践

Squirrel状态机-从原理探究到最佳实践

时间:2023-01-28 16:58:16浏览次数:32  
标签:audit applicationContext Squirrel 状态机 探究 审核 ShopInfoAuditStatusEnum public

作者:京东物流 郑朋辉

1 简介

Squirrel状态机是一种用来进行对象行为建模的工具,主要描述对象在它的生命周期内所经历的状态,以及如何响应来自外界的各种事件。比如订单的创建、已支付、发货、收获、取消等等状态、状态之间的控制、触发事件的监听,可以用该框架进行清晰的管理实现。使用状态机来管理对象生命流的好处更多体现在代码的可维护性、可测试性上,明确的状态条件、原子的响应动作、事件驱动迁移目标状态,对于流程复杂易变的业务场景能大大减轻维护和测试的难度。

2 基本概念

2.1 Squirrel状态机定义

Squirrel状态机是一种有限状态机,有限状态机是指对象有一个明确并且复杂的生命流(一般而言三个以上状态),并且在状态变迁存在不同的触发条件以及处理行为。

2.2 Squirrel状态机要素

Squirrel状态机可归纳为4个要素,即现态、条件、动作、次态。“现态”和“条件”是因,“动作”和“次态”是果。

  • 现态:是指当前所处的状态。
  • 条件:又称为事件。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
  • 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  • 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

3 实现原理

3.1 店铺审核CASE

举例,京东线上开店需要经过审核才能正式上线,店铺状态有待审核、已驳回、已审核,对应操作有提交审核,审核通过,审核驳回动作。现在需要实现一个店铺审核流程的需求。

3.2 方案对比

3.2.1 常用if-else或switch-case实现(分支模式)

图1.if-else/switch-case模式实现流程图

3.2.2 状态机实现

图2.状态机模式实现流程图

3.2.3 对比

通过引入状态机,可以去除大量if-else if-else或者switch-case分支结构,直接通过当前状态和状态驱动表查询行为驱动表,找到具体行为执行操作,有利于代码的维护和扩展。

3.3 实现原理

图3.状态机创建流程图

  • StateMachine: StateMachine实例由StateMachineBuilder创建不被共享,对于使用annotation方式(或fluent api)定义的StateMachine,StateMachine实例即根据此定义创建,相应的action也由本实例执行,与spring的集成最终要的就是讲spring的bean实例注入给由builder创建的状态机实例;
  • StateMachineBuilder: 本质上是由StateMachineBuilderFactory创建的动态代理。被代理的StateMachineBuilder默认实现为StateMachineBuilderImpl,内部描述了状态机实例创建细节包括State、Event、Context类型信息、constructor等,同时也包含了StateMachine的一些全局共享资源包括StateConverter、EventConverter、MvelScriptManager等。StateMachineBuilder可被复用,使用中可被实现为singleton;
  • StateMachineBuilderFactory: 为StateMachineBuilder创建的动态代理实例;

4 实践分享

4.1 环境依赖

<dependency>
<groupId>org.squirrelframework</groupId>
<artifactId>squirrel-foundation</artifactId>
<version>0.3.9</version>
</dependency>

4.2 状态机元素定义:状态、事件

// 店铺审核状态
public Enum ShopInfoAuditStatusEnum{
audit(0,"待审核"),
agree(1,"审核通过"),
reject(2,"审核驳回");
}
// 店铺审核事件
public Enum ShopInfoAuditEvent{
SUBMIT, // 提交
AGREE, // 同意
REJECT; // 驳回
}

4.3 构建StateMachineBuilder实例

/**
* StateMachineBuilder实例
*/
public class StateMachineEngine <T extends UntypedStateMachine, S, E, C> implements ApplicationContextAware{


private ApplicationContext applicationContext;


private static Map<String,UntypedStateMachineBuilder> builderMap = new HashMap<String,UntypedStateMachineBuilder>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}


@Transactional
public void fire(Class<T> machine, S state, E event, C context) {
StateMachineBuilder stateMachineBuilder = this.getStateMachineBuilder(machine);
StateMachine stateMachine = stateMachineBuilder.newStateMachine(state,applicationContext);
stateMachine.fire(event, context);
}


private StateMachineBuilder getStateMachineBuilder(Class<T> stateMachine){
UntypedStateMachineBuilder stateMachineBuilder = builderMap.get(stateMachine.getName());
if(stateMachineBuilder == null){
stateMachineBuilder = StateMachineBuilderFactory.create(stateMachine,ApplicationContext.class);
builderMap.put(stateMachine.getName(),stateMachineBuilder);
}
return stateMachineBuilder;

4.4 创建具体店铺状态审核状态机

/**
* 店铺审核状态机
*/
@States({
@State(name = "audit"),
@State(name = "agree"),
@State(name = "reject")
})
@Transitions({
@Transit(from = "audit", to = "agree", on = "AGREE", callMethod = "agree"),
@Transit(from = "audit", to = "reject", on = "REJECT", callMethod = "reject"),
@Transit(from = "reject", to = "audit", on = "SUBMIT", callMethod = "submit"),
@Transit(from = "agree", to = "audit", on = "SUBMIT", callMethod = "submit"),
@Transit(from = "audit", to = "audit", on = "SUBMIT", callMethod = "submit"),
})
@StateMachineParameters(stateType=ShopInfoAuditStatusEnum.class, eventType=ShopInfoAuditEvent.class, contextType=ShopInfoAuditStatusUpdateParam.class)
public class ShopInfoAuditStateMachine extends AbstractUntypedStateMachine {


private ApplicationContext applicationContext;


public ShopInfoAuditStateMachine(){}


public ShopInfoAuditStateMachine(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}


// 审核通过业务逻辑
public void agree(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.agree(fromState,toState,event,param);
}

// 审核驳回业务逻辑
public void reject(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.reject(fromState,toState,event,param);
}

// 提交业务逻辑
public void submit(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.submit(fromState,toState,event,param);
}

4.5 客户端调用

// 调用端
main{
StateMachineEngine stateMachineEngine = applicationContext.getBean(StateMachineEngine.class);
// 审核通过调case
stateMachineEngine.fire(ShopInfoAuditStateMachine.class,ShopInfoAuditStatusEnum.audit,ShopInfoAuditEvent.AGREE,param);
// 审核驳回case
stateMachineEngine.fire(ShopInfoAuditStateMachine.class,ShopInfoAuditStatusEnum.audit,ShopInfoAuditEvent.REJECT,param);
}

5 总结

状态机很好的帮我们处理了对象状态的流转、事件的监听以及外界的各种事件的响应。从代码设计角度减少了大量if-else/switch-case逻辑判断,提高了代码的可维护性、扩展性,方便管理和测试。

标签:audit,applicationContext,Squirrel,状态机,探究,审核,ShopInfoAuditStatusEnum,public
From: https://www.cnblogs.com/Jcloud/p/17070001.html

相关文章

  • du df 探究
    sudoaptautoremove--purgesnapdncdulsof|grepdelete|sort-nrk7|morelsof-w|grepdelete|sort-nrk7|morehttps://www.bbsmax.com/A/B0zq0KeKdv/htt......
  • Squirrel状态机-从原理探究到最佳实践
    作者:京东物流郑朋辉1简介Squirrel状态机是一种用来进行对象行为建模的工具,主要描述对象在它的生命周期内所经历的状态,以及如何响应来自外界的各种事件。比如订单的创建、......
  • MySQL索引底层探究
    一、什么是索引?索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引是一种数据结构。数据库索引,是数据库......
  • FSM状态机设计
    1.状态机主要分为两类:Moore型&Mealy型Moore状态机:输出仅仅与当前状态有关Mealy状态机:输出不仅取决于当前状态,还和输入有关2.三段式状态机:第一段:时序逻辑描述curr......
  • 用状态机实现通用多字节SPI接口模块
    这次设计一个通用的多字节SPI接口模块,特点如下:可以设置为1-128字节的SPI通信模块可以修改CPOL、CPHA来进行不同的通信模式可以设置输出的时钟 状态转移图和思路与多......
  • 探究:初学者编程语言的选择
    目录前景提要编程语言选择面临的问题零基础的理解可能不一样?真正初学者编程语言选择面临的问题编程语言难易程度问题形成编程思维的人和没有思维的入门者的区别语言难度问......
  • 探究BrainSplit-集群脑裂
    本篇文章将会以redis集群为例,分享在主从集群中会导致数据丢失的一个问题:BrainSplit-集群脑裂1.什么是集群脑裂所谓的脑裂,就是指在主从集群中,同时有两个主节点,它们都能......
  • 逆向原理 | SetWindowsHookEx 原理探究与实验
    逆向原理|SetWindowsHookEx原理探究与实验SetWindowsHook其实是在windows逆向中非常重要的一个api与之对应的是UnhookWindowsHookEx,用于卸载钩子。但是这个api的机制......
  • 有限状态机
    AbstractFSM在数字电路中非常重要,借由FSM,数字电路也能循序地执行起算法。本文将详细讨论各种FSMcodingstyle的优缺点,并归纳出推荐的codingstyle。1.MooreFSM的架构2......
  • 16进制枚举状态机学习
    转自:https://blog.csdn.net/wodeni512517/article/details/711234691.介绍十六进制:typedefenum{ACTION_SHOWCARDS=0x01,//1ACTION_FOLLOW=0x02,//2A......