• 【架构设计】无状态状态机在代码中的实践


    无状态状态机

    一:前言

    ​ 在项目中经常有一些工单,申请之类需要对状态进行流转。这种需求一般都是满足什么条件然后就翻转状态。这些流程结构相似得逻辑,感觉可以抽象处理。用一个通用得结构处理,可以让系统更加整洁,代码逻辑更加单一。

    ​ 发现阿里开源一种,轻量级得无状态状态机得组件。仔细研究一下,确实很适合这种场景下对代码逻辑得解耦,相比于if-else代码更加让人容易理解,也更加优雅。

    二:状态机的模型

    • State:状态
    • Event:事件,状态由事件触发,引起变化
    • Transition:流转,表示从一个状态到另一个状态
    • External Transition:外部流转,两个不同状态之间的流转
    • Internal Transition:内部流转,同一个状态之间的流转
    • Condition:条件,表示是否允许到达某个状态
    • Action:动作,到达某个状态之后,可以做什么
    • StateMachine:状态机

    三:怎么使用

    ​ 这里我们假设几个简单的逻辑需要处理:

    • 我们需要从待审核的状态需要流转到审核通过的状态,审核前需要做一个审核校验,审核通过后需要发送短信通知用户。

    外部状态流转实现:

    1. 定义状态枚举(待审核,审核通过,拒绝)
     static enum States {
        WAITE, PASS, REJECT
    }
    
    1. 定义一个事件枚举,审核事件/审核拒绝/提交申请/内部状态流转
    static enum Events {
       AUDIT, AUDIT_REJECT, COMMIT, COMPLETE_INFORMATION
    }
    
    // 上下文对象
    static class Context{
       String operator = "flw";
       String entityId = "7758258";
     }
    
    1. 按照上面需求配置一个状态机
       StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
            builder.externalTransition()    // 外部状态流转
                    .from(States.WAITE)     // 起始状态:待审核
                    .to(States.PASS)        // 目的状态:审核通过
                    .on(Events.AUDIT)       // 事件:审核事件
                    .when(checkCondition()) // 流转需要校验的条件,校验不通过不会进行doAction
                    .perform(doAction());   // 执行流转操作
    
       StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID);
       // 打印状态机里面的流程流转图谱
       stateMachine.showStateMachine();
    
       private Condition<StateMachineMyTest.Context> checkCondition() {
            return (ctx) -> {return true;}; // 默认返回true
        }
    
        private Action<StateMachineMyTest.States, StateMachineMyTest.Events, StateMachineMyTest.Context> doAction() {
            return (from, to, event, ctx)->{
                System.out.println(ctx.operator+" is operating "+ctx.entityId+" from:"+from+" to:"+to+" on:"+event);
            };
        }
    

    执行状态机的打印图谱结果:

    -----StateMachine:TestStateMachine-------
    State:PASS
    State:WAITE
        Transition:WAITE-[AUDIT, EXTERNAL]->PASS
    ------------------------
    
    1. 执行状态机
    // 通过状态机执行 待审核状态执行审核操作,
    States target = stateMachine.fireEvent(States.WAITE, Events.AUDIT, new Context());
    Assert.assertEquals(States.PASS, target); // 成功就会返回目标状态机,校验失败就会返回原来的状态
    

    执行结果:

    flw is operating 7758258 from:WAITE to:PASS on:AUDIT
    

    如果 checkCondition 返回false ,就不会执行doAction 操作。

    内部状态流转实现

    • 假设现在只是用户补全资料,只需要进行一些更新数据操作,不需要状态流转。这种需求可以通过内部状态流转实现
     @Test
        public void testExternalNormal(){
            StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
            builder.externalTransition()// 内部流转
                    .from(States.WAITE)
                    .to(States.PASS)
                    .on(Events.COMPLETE_INFORMATION)
                    .when(checkCondition())
                    .perform(doAction());
    
            StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID);
            // 打印状态机里面的流程流转图谱
            stateMachine.showStateMachine();
            // 通过状态机执行 待审核状态执行审核操作,
            States target = stateMachine.fireEvent(States.WAITE, Events.AUDIT, new Context());
            Assert.assertEquals(States.WAITE, target);
        }
    

    执行结果:

    -----StateMachine:TestStateMachine-------
    State:PASS
    State:WAITE
        Transition:WAITE-[COMPLETE_INFORMATION, EXTERNAL]->PASS
    ------------------------
    

    对于方法里面的异常也会抛出来,也是支持事务操作。

    整体的流程图如下:

    image-20211015223159331

    四:总结

    ​ 状态机非常轻量,支持事务操作,对于状态流转比较对的场景逻辑解耦还是比较优雅的。

    链接:https://github.com/alibaba/COLA/tree/master/cola-components/cola-component-statemachine

  • 相关阅读:
    C++默认参数
    C语言中volatile关键字的作用
    CURL超时处理
    C语言中全局变量、局部变量、静态全局变量、静态局部变量的区别
    unix时间戳和localtime
    !!的用处
    linux中grep和egrep的用法
    非阻塞,send后马上close消息能成功发出去吗
    .hpp与.h的区别
    14课作业答疑
  • 原文地址:https://www.cnblogs.com/simple-flw/p/15413022.html
Copyright © 2020-2023  润新知