您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Squirrel状态机-从原理探究到最佳实践
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Squirrel状态机-从原理探究到最佳实践
自猿其说Tech
2022-12-21
IP归属:未知
46640浏览
# 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实现(分支模式) ![](//img1.jcloudcs.com/developer.jdcloud.com/47f5c883-71db-4370-8cea-63d90c756a7520221221161010.png) <center>图1.if-else/switch-case模式实现流程图</center> ### 3.2.2 状态机实现 ![](//img1.jcloudcs.com/developer.jdcloud.com/3260d8db-4844-4dc2-b73a-2c690cb5fb9b20221221161046.png) <center>图2.状态机模式实现流程图</center> ### 3.2.3 对比 通过引入状态机,可以去除大量if-else if-else或者switch-case分支结构,直接通过当前状态和状态驱动表查询行为驱动表,找到具体行为执行操作,有利于代码的维护和扩展。 ## 3.3 实现原理 ![](//img1.jcloudcs.com/developer.jdcloud.com/0a39fd44-205f-4d1c-b263-f83c2fba784520221221161116.png) <center>图3.状态机创建流程图</center> - 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 环境依赖 ```java <dependency> <groupId>org.squirrelframework</groupId> <artifactId>squirrel-foundation</artifactId> <version>0.3.9</version> </dependency> ``` ## 4.2 状态机元素定义:状态、事件 ```java // 店铺审核状态 public Enum ShopInfoAuditStatusEnum{ audit(0,"待审核"), agree(1,"审核通过"), reject(2,"审核驳回"); } // 店铺审核事件 public Enum ShopInfoAuditEvent{ SUBMIT, // 提交 AGREE, // 同意 REJECT; // 驳回 } ``` ## 4.3 构建StateMachineBuilder实例 ```java /** * 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 创建具体店铺状态审核状态机 ```java /** * 店铺审核状态机 */ @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 客户端调用 ```java // 调用端 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逻辑判断,提高了代码的可维护性、扩展性,方便管理和测试。 ------------ 自猿其说Tech-JDL京东物流技术与数据智能部 **作者:郑朋辉**
原创文章,需联系作者,授权转载
上一篇:金融数智化体系建设-零开发精运营(数据到运营策略的最后一公里)
下一篇:Airtest图像识别测试工具原理解读&最佳实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号