轻量级状态机框架 Sateless4j 实践

状态机选型

  • squirrel-foundation
  • Spring statemachine
  • stateless4j

关于这几个对比,文章比较多,这里就不赘述了。

这三个,我基本都有直接或间接使用过。

简单感受是:

squirrel-foundation,同事用过,功能丰富,较为轻量,上手简单。

Spring statemachine,自己调研过,和 Spring 天然集成,注解声明,功能丰富,同时上手较复杂,状态机实例不能单例使用,线程不安全。

stateless4j ,轻量、简单,轻度使用,很 nice,对代码侵入极小。GitHub - stateless4j/stateless4j: Lightweight Java State Machine

实践

质量检测任务(简称:质检任务)的状态流转图:

new 一个类,名为:QcStateMachine 质检状态机

依据上面的状态转移图,配置状态转移。

提前准备两个枚举类:状态枚举、时间枚举。前置态-接受到事件->后置态

    private static final StateMachineConfig<QualityStatusEnum, QualityEventEnum> CONFIG = new StateMachineConfig<>();

    static {
        /*
         * 最初为 INIT 状态时
         */
        CONFIG.configure(QualityStatusEnum.INIT)
                // .permitDynamic(new TriggerWithParameters1<>(QualityEventEnum.APPLY_QUALITY_TASK, QcTask.class), qcTask -> {
                //     return QualityStatusEnum.CHECKING;
                // })
                .permit(QualityEventEnum.APPLY_QUALITY_TASK, QualityStatusEnum.CHECKING)
                .permit(QualityEventEnum.SAVE_QUALITY_RESULT, QualityStatusEnum.CHECKING)
                .permit(QualityEventEnum.SUBMIT_QUALITY_RESULT, QualityStatusEnum.RECHECKING)
                .ignore(QualityEventEnum.DELETE);

        CONFIG.configure(QualityStatusEnum.CHECKING)
                .ignore(QualityEventEnum.SAVE_QUALITY_RESULT)
                .permit(QualityEventEnum.SUBMIT_QUALITY_RESULT, QualityStatusEnum.RECHECKING);

        CONFIG.configure(QualityStatusEnum.RECHECKING)
                .ignore(QualityEventEnum.SUBMIT_RECHECK_RESULT)
                .permit(QualityEventEnum.RECHECK_EXPIRE, QualityStatusEnum.RECHECKED);

        CONFIG.configure(QualityStatusEnum.RECHECKED)
                .permit(QualityEventEnum.AMEND, QualityStatusEnum.AMENDED)
                .permit(QualityEventEnum.AMEND_EXPIRE, QualityStatusEnum.AMENDED);

    }

//构建状态机实例,传入当前状态和状态转移配置
StateMachine<QualityStatusEnum, QualityEventEnum> sm = new StateMachine<>(current, CONFIG)
//判断当前状态能不能接受目标事件: 提交质检结果
if (sm.canFire(QualityEventEnum.SUBMIT_QUALITY_RESULT)) {
  // 中断
}

//接受事件,状态转移到下一个状态
sm.fire();

//更新表里的状态
QualityStatusEnum nextState = sm.getState(); //推荐这样获取下一个状态,减少硬编码
...


上面时最简单的轻量使用。

如果需要在状态转移时,伴随一些动作逻辑,可以在状态转移配置中设置。

QcStateMachine 完整代码:

import com.github.oxo42.stateless4j.StateMachine;
import com.github.oxo42.stateless4j.StateMachineConfig;
import com.sankuai.groceryrisk.common.core.exception.DialogException;
import com.sankuai.groceryrisk.risk.investigation.service.constant.enums.QualityEventEnum;
import com.sankuai.groceryrisk.risk.investigation.service.constant.enums.QualityStatusEnum;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 *
 * @author L&J
 * @version 0.1
 * @since 2023/2/4 12:10
 */
@Slf4j
public class QcStateMachine {

    private static final StateMachineConfig<QualityStatusEnum, QualityEventEnum> CONFIG = new StateMachineConfig<>();

    static {
        /*
         * 最初为 INIT 状态时
         */
        CONFIG.configure(QualityStatusEnum.INIT)
                // .permitDynamic(new TriggerWithParameters1<>(QualityEventEnum.APPLY_QUALITY_TASK, QcTask.class), qcTask -> {
                //     return QualityStatusEnum.CHECKING;
                // })
                .permit(QualityEventEnum.APPLY_QUALITY_TASK, QualityStatusEnum.CHECKING)
                .permit(QualityEventEnum.SAVE_QUALITY_RESULT, QualityStatusEnum.CHECKING)
                .permit(QualityEventEnum.SUBMIT_QUALITY_RESULT, QualityStatusEnum.RECHECKING)
                .ignore(QualityEventEnum.DELETE);

        CONFIG.configure(QualityStatusEnum.CHECKING)
                .ignore(QualityEventEnum.SAVE_QUALITY_RESULT)
                .permit(QualityEventEnum.SUBMIT_QUALITY_RESULT, QualityStatusEnum.RECHECKING);

        CONFIG.configure(QualityStatusEnum.RECHECKING)
                .ignore(QualityEventEnum.SUBMIT_RECHECK_RESULT)
                .permit(QualityEventEnum.RECHECK_EXPIRE, QualityStatusEnum.RECHECKED);

        CONFIG.configure(QualityStatusEnum.RECHECKED)
                .permit(QualityEventEnum.AMEND, QualityStatusEnum.AMENDED)
                .permit(QualityEventEnum.AMEND_EXPIRE, QualityStatusEnum.AMENDED);

    }

    public static StateMachine<QualityStatusEnum, QualityEventEnum> of(Integer sourceState) {
        return of(QualityStatusEnum.getByValue(sourceState));
    }

    public static StateMachine<QualityStatusEnum, QualityEventEnum> of(QualityStatusEnum sourceState) {
        return new StateMachine<>(sourceState, CONFIG);
    }

    public static boolean canFire(Integer current, QualityEventEnum event) {
        return canFire(QualityStatusEnum.getByValue(current), event);
    }

    /**
     * 当前状态是否接受当前事件
     * @param current 当前状态, 前置态
     * @param event 事件
     */
    public static boolean canFire(QualityStatusEnum current, QualityEventEnum event) {
        StateMachine<QualityStatusEnum, QualityEventEnum> sm = new StateMachine<>(current, CONFIG);
        return sm.canFire(event);
    }

    public static StateMachine<QualityStatusEnum, QualityEventEnum> checkFireOrThrow(Integer current, QualityEventEnum event) {
        return checkFireOrThrow(QualityStatusEnum.getByValue(current), event);
    }

    public static StateMachine<QualityStatusEnum, QualityEventEnum> checkFireOrThrow(QualityStatusEnum current, QualityEventEnum event) {
        StateMachine<QualityStatusEnum, QualityEventEnum> sm = new StateMachine<>(current, CONFIG);
        if (!sm.canFire(event)) {
            throw new DialogException("当前任务状态('{}')不可'{}'", current.getLabel(), event.getLabel());
        }
        return sm;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值