阿里状态机引擎实现

状态机的技术选型看这篇就够了,最后一个直叫好! - 掘金

实现一个状态机引擎,教你看清DSL的本质_cola状态机-CSDN博客

一、引入jar包

<!--阿里状态机jar-->
<dependency>
	<groupId>com.alibaba.cola</groupId>
	<artifactId>cola-component-statemachine</artifactId>
	<version>4.3.2</version>
</dependency>        

二、引入流转类型枚举

package com.lx.designPattern.statepattern.statemachine.enums;

/**
 * 流转类型枚举
 * @author lwp
 * @date 2023-07-06 14:56:27
 * @version 1.0
 */
public enum TransitionTypeEnum {

    /**
     * 内部流转
     */
    INTERNAL,

    /**
     * 外部流转
     */
    EXTERNAL,

    /**
     * 多状态外部流转
     */
    EXTERNALS;
}

三、引入事件枚举

package com.lx.designPattern.statepattern.statemachine.enums;

/**
 * 履约状态事件枚举
 *
 * @author lwp
 * @version 1.0
 * @date 2023-07-06 13:40:11
 */
public enum FulfillmentStatusEventEnum {

    /**
     * 开始租赁非标商品履约
     */
    BEGIN_RENT_NON_STANDARD_GOODS_FULFILLMENT,

    /**
     * 完成资源匹配
     */
    MATCH_RESOURCE,

    /**
     * 完成租赁交付
     */
    COMPLETE_RENT_DELIVER,

    /**
     * 重置履约计划
     */
    RESET_FULFILLMENT,

    /**
     * 取消履约单
     */
    CANCEL_FULFILLMENT,

    /**
     * 创建售车交付履约单
     */
    CREATE_SALE_DELIVER_FULFILLMENT,

    /**
     * 完成服务执行中
     */
    COMPLETE_SERVICE_FULFILLMENT,

    /**
     * 非灰度履约单交付
     */
    NON_GRAY_DELIVER,

    /**
     * 欢乐租备车
     */
    HAPPY_RENT_PLAN_CAR,

    /**
     * 开始替换车履约
     */
    START_REPLACE_DELIVER_FULFILLMENT,
    /**
     * 开始常规租赁退车履约
     */
    START_RENT_BACK_CAR_FULFILLMENT,
    /**
     * 完成替换车车退车
     */
    COMPLETE_REPLACE_BACK_CAR_FULFILLMENT,
    /**
     * 完成租赁退车
     */
    COMPLETE_RENT_BACK_CAR_FULFILLMENT,
    /**
     * 取消履约 (新的)
     */
    CANCEL_FULFILLMENT_2ND,
    /**
     * 完成服务履约
     */
    COMPLETE_VEHICLE_SERVICE,

    /**
     * 渠道商履约
     */
    CHANNEL_FULFILLMENT,
    ;
}

四、引入流转状态枚举

package com.lx.designPattern.statepattern.statemachine.enums;

import com.lx.exception.BusinessException;

import java.util.Objects;

/**
 * 履约单状态枚举
 * @author lwp
 * @date 2023/1/5 9:16
 * @version 1.0
 */
public enum FulfillmentStatusEnum {

    /**
     * 初始状态
     */
    INITIAL(0, "初始状态"),

    /**
     * 待匹配
     */
    WAIT_MATCH(2, "待匹配"),
    /**
     * 进行中
     */
    IN_PROGRESS(3, "进行中"),
    /**
     * 已完成
     */
    COMPLETED(4, "已完成"),
    /**
     * 已取消
     */
    CANCELED(5, "已取消"),
    ;

    private Integer status;
    private String desc;

    FulfillmentStatusEnum(Integer status, String desc) {
        this.status = status;
        this.desc = desc;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static FulfillmentStatusEnum getByStatus(Integer status) {
        for (FulfillmentStatusEnum fulfillmentStatusEnum : FulfillmentStatusEnum.values()) {
            if (Objects.equals(status, fulfillmentStatusEnum.getStatus())) {
                return fulfillmentStatusEnum;
            }
        }
        throw new BusinessException("未找到履约状态枚举");
    }
}
 1.需要处理的业务参数类
package com.lx.designPattern.statepattern.statemachine.dto;

import lombok.Data;

/**
 * 履约单dto
 * @author lwp
 * @date 2023-07-25 16:22:04
 * @version 1.0
 */
@Data
public class FulfillmentBillDTO {

    /**
     * 交易订单
     */
    private A a;

    /**
     * 履约主单
     */
    private B b;

    /**
     * 车辆履约子单
     */
    private C c;
}

五、准备状态机

package com.lx.designPattern.statepattern.statemachine;

import com.alibaba.cola.statemachine.StateMachine;
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.lx.designPattern.statepattern.statemachine.statustransition.FulfillmentStatusTransition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * 履约状态机
 *
 * @author lwp
 * @version 1.0
 * @date 2023-07-27 10:31:27
 */
@Slf4j
@Lazy
@Component
public class FulfillmentStatusStateMachine {

    /**
     * 状态机ID
     */
    private static final String MACHINE_ID = "FulfillmentStatusStateMachine";

    /**
     * 状态机
     */
    private StateMachine<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachine;

    @Autowired
    private List<FulfillmentStatusTransition> fulfillmentStatusTransitions;

    /* ******************************* 履约单状态流转 *****************************/

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        // 创建状态机
        StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> stateMachineBuilder
                = StateMachineBuilderFactory.create();
        // 添加没有命中配置规则时的回调
        stateMachineBuilder.setFailCallback(this::stateMachineFailCallback);
        // 初始化transition
        initTransition(stateMachineBuilder);
        stateMachine = stateMachineBuilder.build(MACHINE_ID);
    }

    /**
     * 触发流转
     */
    public FulfillmentStatusEnum fireEvent(FulfillmentStatusEnum status,
                                           FulfillmentStatusEventEnum event,
                                           FulfillmentBillDTO fulfillmentBill) {
        FulfillmentStatusEnum resultStatus = stateMachine.fireEvent(status, event, fulfillmentBill);
        // 如果结果状态和源状态相同,代表流转失败
        if (resultStatus == status) {
            log.warn("履约单{}状态流转失败, from:{}, to:{}, event:{}",
                    fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
                    status.getStatus(),
                    resultStatus.getDesc(),
                    event);
        } else {
            log.info("履约单{}状态流转, from:{}, to:{}, event:{}",
                    fulfillmentBill.getMainFulfillmentBill().getFulfillmentCode(),
                    status.getStatus(),
                    resultStatus.getDesc(),
                    event);
        }
        return resultStatus;
    }

    /**
     * 没有命中配置规则时的回调
     */
    private void stateMachineFailCallback(FulfillmentStatusEnum status,
                                          FulfillmentStatusEventEnum event,
                                          FulfillmentBillDTO fulfillmentBill) {
        log.error("履约单{}状态流转失败: 未找到匹配的流转规则, from:{}, event:{}",
                fulfillmentBill.getMainFulfillmentBill().getId(),
                status.getDesc(),
                event);
    }

    /**
     * 初始化transition
     */
    private void initTransition(StateMachineBuilder<FulfillmentStatusEnum, FulfillmentStatusEventEnum,
            FulfillmentBillDTO> builder) {
        fulfillmentStatusTransitions.forEach(transition -> {
            switch (transition.getTransitionType()) {
                case INTERNAL:
                    if (transition.getWithin().isPresent()) {
                        builder.internalTransition()
                                .within(transition.getWithin().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单内部状态流转错误: 缺少within参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                case EXTERNAL:
                    if (transition.getFrom().isPresent() && transition.getTo().isPresent()) {
                        builder.externalTransition()
                                .from(transition.getFrom().get())
                                .to(transition.getTo().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单外部状态流转错误: 缺少from或to参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                case EXTERNALS:
                    if (transition.getFromAmong().isPresent() && transition.getTo().isPresent()) {
                        builder.externalTransitions()
                                .fromAmong(transition.getFromAmong().get())
                                .to(transition.getTo().get())
                                .on(transition.getEvent())
                                .when(transition.getCondition())
                                .perform(transition.getAction());
                    } else {
                        log.error("初始化履约单多状态外部状态流转错误: 缺少fromAmong或to参数");
                        throw new IllegalArgumentException("履约状态状态机初始化失败");
                    }
                    break;
                default:
                    log.error("不支持的流转类型:{}", transition.getTransitionType());
            }
        });
    }
}

六、准备流转接口

package com.lx.designPattern.statepattern.statemachine.statustransition;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;

import java.util.Optional;

/**
 * 履约单状态流转
 * @author lwp
 * @date 2023-07-06 15:08:18
 * @version 1.0
 */
public interface FulfillmentStatusTransition {

    /**
     * 获取类转类型
     * @return 流转类型
     */
    TransitionTypeEnum getTransitionType();

    /**
     * 获取within参数(内部流转必需)
     * @return within
     */
    default Optional<FulfillmentStatusEnum> getWithin() {
        return Optional.empty();
    }

    /**
     * 获取from参数(外部流转必需)
     * @return from
     */
    default Optional<FulfillmentStatusEnum> getFrom() {
        return Optional.empty();
    }

    /**
     * 获取fromAmong参数(多状态外部流转必需)
     * @return fromAmong
     */
    default Optional<FulfillmentStatusEnum[]> getFromAmong() {
        return Optional.empty();
    }

    /**
     * 获取to参数(外部流转和多状态外部流转必需)
     * @return to
     */
    default Optional<FulfillmentStatusEnum> getTo() {
        return Optional.empty();
    };

    /**
     * 获取event
     * @return on参数
     */
    FulfillmentStatusEventEnum getEvent();

    /**
     * 获取condition
     * @return when
     */
    Condition<FulfillmentBillDTO> getCondition();

    /**
     * 获取action
     * @return preform
     */
    Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction();
}

七、实现流转接口和定义流转规则

package com.lx.designPattern.statepattern.statemachine.statustransition;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import com.lx.designPattern.statepattern.statemachine.enums.TransitionTypeEnum;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * 完成履约状态流转
 * @author lwp
 * @date 2023-07-12 10:30:32
 * @version 1.0
 */
@Component
public class CompleteFulfillmentTransition implements FulfillmentStatusTransition {

    //@Autowired
    //private FulfillmentBillDaoService fulfillmentBillDaoService;

    @Override
    public TransitionTypeEnum getTransitionType() {
        return TransitionTypeEnum.EXTERNAL;
    }

    @Override
    public Optional<FulfillmentStatusEnum> getFrom() {
        return Optional.of(FulfillmentStatusEnum.IN_PROGRESS);
    }

    @Override
    public Optional<FulfillmentStatusEnum> getTo() {
        return Optional.of(FulfillmentStatusEnum.COMPLETED);
    }

    @Override
    public FulfillmentStatusEventEnum getEvent() {
        return FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER;
    }

    @Override
    public Condition<FulfillmentBillDTO> getCondition() {
        return (fulfillmentBillDTO -> true);
    }

    @Override
    public Action<FulfillmentStatusEnum, FulfillmentStatusEventEnum, FulfillmentBillDTO> getAction() {
        return (srcState, tarState, event, fulfillmentBillDTO) -> {
            // 修改履约单状态
            MainFulfillmentBill updateMainBill = new MainFulfillmentBill();
            updateMainBill.setId(fulfillmentBillDTO.getMainFulfillmentBill().getId());
            updateMainBill.setStatus(tarState.getStatus());
            //fulfillmentBillDaoService.updateMainBillById(updateMainBill);
            System.out.println("状态改为完成了");
        };
    }
}

八、准备测试类测试

package com.lx.designPattern;

import com.lx.designPattern.statepattern.statemachine.FulfillmentStatusStateMachine;
import com.lx.designPattern.statepattern.statemachine.business.InsuranceStatusChangeServiceImpl;
import com.lx.designPattern.statepattern.statemachine.dto.FulfillmentBillDTO;
import com.lx.designPattern.statepattern.statemachine.dto.MainFulfillmentBill;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEnum;
import com.lx.designPattern.statepattern.statemachine.enums.FulfillmentStatusEventEnum;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Desc 阿里状态机测试类
 * @author lwp
 * @version 1.0
 * @date 2024-01-13 22:16:22
 */
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "dev")
public class StateMachineTest {

    @Autowired
    private FulfillmentStatusStateMachine fulfillmentStatusStateMachine;

    @Test
    public void handStatusChangeComplete() {
        FulfillmentBillDTO billDTO = new FulfillmentBillDTO();
        MainFulfillmentBill mainFulfillmentBill = new MainFulfillmentBill();
        mainFulfillmentBill.setFulfillmentCode("LY001");
        mainFulfillmentBill.setStatus(1);
        billDTO.setMainFulfillmentBill(mainFulfillmentBill);
        fulfillmentStatusStateMachine.fireEvent(FulfillmentStatusEnum.getByStatus(3),
                FulfillmentStatusEventEnum.COMPLETE_RENT_DELIVER,billDTO);
    }

    
}

 九、测试效果如下图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/319238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python | 三、函数

函数的形参和实参&#xff08;对应卡码网11题句子缩写&#xff09; 除非实参是可变对象&#xff0c;如列表、字典和集合&#xff0c;则此时形参会复制实参的地址&#xff0c;即此时二者指向同一个地址&#xff0c;因此在函数内对形参的操作会影响到实参除这种情况外&#xff0…

Spring自带分布式锁你用过吗?

环境&#xff1a;SpringBoot2.7.12 本篇文章将会为大家介绍有关spring integration提供的分布式锁功能。 1. 简介 Spring Integration 是一个框架&#xff0c;用于构建事件驱动的应用程序。在 Spring Integration 中&#xff0c;LockRegistry 是一个接口&#xff0c;用于管理…

推荐两款好用的卫星地图。

问题描述&#xff1a;推荐两款好用的卫星地图。 问题解决&#xff1a;谷歌地球、高德卫星地图。个人感觉谷歌地球好用一些。

ST工具Flash Loader烧写STM32

简介 使用ST公司自家的Flash Loader烧写程序&#xff0c; 如下图, F103直接接USART1到PC端就好, 使用普通的USB转TTL线&#xff0c; 就是你之前使用串口打印的方式连接到电脑就好。 软件下载 ST Flash Loader 我放到CSDN里面了Flash_Loader_demo_v2.8.0 开发板设置 Boot0-&g…

序章 熟悉战场篇—了解vue的基本操作

了解vue 的基本目录&#xff1a; dist 是打包后存放的目录(后续可以改)node_modules 是依赖包public 是静态index页面src 是存放文件的目录assets 是存放静态资源的目录components 是存放组件的目录views 是存放页面文件的目录&#xff08;没有views 自己新建一个&#xff09;A…

动态规划篇-03:打家劫舍

198、打家劫舍 状态转移方程 base case 边界问题就是&#xff1a;走到最后一间房子门口也没抢&#xff0c;那么最终抢到的金额为0 明确状态 “原问题和子问题中会变化的变量” 抢到的金额数就是状态&#xff0c;因为随着在每一件房子门口做选择&#xff0c;抢到的金额数会随…

Unity中的异步编程【7】——在一个异步方法里播放了animation动画,取消任务时,如何停止动画播放

用一个异步方法来播放一个动画&#xff0c;正常情况是&#xff1a;动画播放结束时&#xff0c;异步方法宣告结束。那如果我提前取消这个异步任务&#xff0c;那在这个异步方法里面&#xff0c;我要怎么停止播放呢&#xff1f;&#xff01; 一、播放animation动画的异步实现 1…

RIP【新华三与华为区别】

【介绍】 rip分为rip 1 与 rip 2 &#xff0c;rip 2 是对 rip 1 的一种升级&#xff0c;rip 2 可以进行认证等功能 【命令】 新华三&#xff1a; [HC3-R1] rip #启用rip [HC3-R1-rip] version 2 #告知rip 版本号 [HC3-R1-rip] network 192.168.1.0 #宣告其网段 [HC3-R1-rip] …

【AIGC】电影风格的一组绝美高清图提示词解析

实际示例 女人主角&#xff0c;以时尚电影风格为灵感&#xff0c;追求照片般的逼真度&#xff0c;运用伦勃朗式光线&#xff0c;创造奇幻且细节丰富的场景&#xff0c;充满象征意义&#xff0c;使用3D渲染技术达到8K超高清晰度。 分类相关信息主角女人风格时尚电影风格逼真度…

银行储蓄系统的顶层数据流图及细化数据流图

绘制出银行储蓄系统的顶层数据流图及细化数据流图&#xff1b; 银行储蓄系统存、取款流程如下&#xff1a; 1&#xff09;业务员事先录入利率信息&#xff1b; 2&#xff09;如果是存款&#xff0c;储户填写存款单&#xff0c;业务员将存款单键入系统&#xff0c;系统更新储户存…

力扣周赛第二题,下午更新后两道

本题中其实看着条件很多&#xff0c;但是仔细读一下会发现&#xff0c;前四个条件都是固定条件。然后我们再看题。 我们的暴力做法是遍历a数组的字符串a的下标起始下标&#xff0c;然后遍历b数组的字符串b的下标起始下标&#xff0c;进行判断&#xff0c;但是这样会超时&#x…

[软件工具]通用OCR识别文字识别中文识别服务程序可局域网访问

【软件界面】 【算法介绍】 采用业界最先进算法之一paddlocr&#xff0c;PaddleOCR&#xff0c;全称PaddlePaddle OCR&#xff0c;是一种基于深度学习的光学字符识别&#xff08;OCR&#xff09;技术。相较于传统的OCR技术&#xff0c;PaddleOCR具有许多优点。 首先&#xff0…

如何创建一个pytorch的训练数据加载器(train_loader)用于批量加载训练数据

Talk is cheap,show me the code! 哈哈&#xff0c;先上几段常用的代码&#xff0c;以语义分割的DRIVE数据集加载为例&#xff1a; DRIVE数据集的目录结构如下&#xff0c;下载链接DRIVE,如果官网下不了&#xff0c;到Kaggle官网可以下到&#xff1a; 1. 定义DriveDataset类&…

Kibana:使用反向地理编码绘制自定义区域地图

Elastic 地图&#xff08;Maps&#xff09;附带预定义区域&#xff0c;可让你通过指标快速可视化区域。 地图还提供了绘制你自己的区域地图的功能。 你可以使用任何您想要的区域数据&#xff0c;只要你的源数据包含相应区域的标识符即可。 但是&#xff0c;当源数据不包含区域…

Spring集成

目录 概述1 声朋一个简单的集成流1.1 使用XML定义集成流1.2 使用Java配置集成流1.3 使用Spring lntegration 的 DSL 配置 2 Spring integration 功能概览2.1 消息通道2.2 过滤器2.3 转换器2.4 路由器2.5 切分器2.6 服务激活器2.7 网关2.8 通道适配器2.9 端点模块 概述 就像我们…

RibbonGroup 添加QLineEdit

RibbonGroup添加QLineEdit&#xff1a; QLineEdit* controlEdit new QLineEdit(); controlEdit->setToolTip(tr("Edit")); controlEdit->setText(tr("Edit")); controlEdit->setMinimumWidth(150); …

vue知识-04

计算属性computed 注意&#xff1a; 1、计算属性是基于它们的依赖进行缓存的 2、计算属性只有在它的相关依赖发生改变时才会重新求值 3、计算属性就像Python中的property&#xff0c;可以把方法/函数伪装成属性 4、computed: { ... } 5、计算属性必须要有…

Windows python下载

1、下载 进入到地址&#xff1a;https://www.python.org/dowmloads 可以直接下载最新的版本 或者点击Windows&#xff0c;查看下方更多的版本 点击文档就下载下来啦 2、安装 双击下载的文件&#xff0c;勾选Add python.exe to PATH添加到环境变量中&#xff0c;选择Coutomi…

【数据结构】树和二叉树堆(基本概念介绍)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm1001.2014.3001.5482 ​​ 目录 前言 树的概念 树的常见名词 树与…

Linux工具-搭建文件服务器

当我们使用linux系统作为开发环境时&#xff0c;经常需要在Linux系统之间、Linux和Windows之间传输文件。 对少量文件进行传输时&#xff0c;可以使用scp工具在两台主机之间实现文件传输&#xff1a; rootubuntu:~$ ssh --help unknown option -- - usage: ssh [-46AaCfGgKkMN…