首页 > 其他分享 >状态机入门实践

状态机入门实践

时间:2024-03-29 21:35:01浏览次数:25  
标签:DELIVERY return 入门 stateMachine 实践 状态机 OrderStatus public

状态机是“有限状态自动机”的简称,是一种描述和处理事物状态变化的数学模型。本质上来讲,就是一种比if...else结构更加优雅,并具备可扩展性的状态转移处理机制。有多种实现方案,如:枚举,Spring Statemachinecola state machine

枚举状态机

通过在枚举中定义方法来实现状态转移,状态定义及转换图示例如下。
枚举状态转换

public enum FlowState {
    SUBMIT_APPLY {
        FlowState transition(String condition) {
            System.out.println(String.format("员工提交申请,同步流转到部门经理申请,参数:%s", condition));
            return DEPARTMENT_MANAGER_AUDIT;
        }
    },
    DEPARTMENT_MANAGER_AUDIT {
        FlowState transition(String condition) {
            System.out.println(String.format("部门经理审批完成,同步流转到HR审批,参数:%s", condition));
            return HR;
        }
    },
    HR {
        FlowState transition(String condition) {
            System.out.println(String.format("HR审批通过,流转到结束组件,参数:%s", condition));
            return END;
        }
    },
    END {
        FlowState transition(String condition) {
            System.out.println(String.format("流程结束,参数:%s", condition));
            return this;
        }
    };

    // 在枚举中可以定义抽象方法,然后在具体的枚举实例中实现该方法
    abstract FlowState transition(String condition);
}

枚举状态机使用示例:

public class EnumStateMachineSample {
    private FlowState flowState;
    public EnumStateMachineSample() {
        this.flowState = FlowState.SUBMIT_APPLY;
    }

    public void perform(String condition) {
        flowState = flowState.transition(condition);
    }

    public static void main(String[] args) {
        EnumStateMachineSample sample = new EnumStateMachineSample();
        sample.perform("arg1");
        sample.perform("arg2");
        sample.perform("arg3");
        sample.perform("arg4");
    }
}

输出:

员工提交申请,同步流转到部门经理申请,参数:arg1
部门经理审批完成,同步流转到HR审批,参数:arg2
HR审批通过,流转到结束组件,参数:arg3
流程结束,参数:arg4

如上,在运行枚举状态机之后,各个状态的转换按预定方式执行。

Spring Statemachine

依赖Spring框架,具备完整的状态机功能设计。
状态及转换图设计如下:
SpringStateMachine_状态转换

添加依赖:

<!-- spring-statemachine-core -->
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>3.0.1</version>
</dependency>
<!-- spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.8</version>
</dependency>

通过注解方式配置状态机:

@Configuration
@EnableStateMachine
public class StateMachineConfiguration extends StateMachineConfigurerAdapter<String, String> {
    private static final Logger LOGGER = LoggerFactory.getLogger(StateMachineConfiguration.class);

    @Override
    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
        // 定义初始节点,结束节点,状态节点
        states.withStates()
                .initial("SS") // 初始节点
                .end("SF") // 结束节点
                .states(new HashSet<String>(Arrays.asList("S1", "S2"))); // 状态节点
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
        // 配置状态节点的事件,流向以及动作
        transitions.withExternal() // 外部流转
                .source("SS").target("S1").event("E1").action(initAction())
                .and()
                .withExternal()
                .source("S1").target("S2").event("E2").action(s1Action())
                .and()
                .withExternal()
                .source("S2").target("SF").event("E3").action(s2Action());
    }

    @Bean
    public Action<String, String> initAction() {
        return new Action<String, String>() {
            public void execute(StateContext<String, String> context) {
                LOGGER.info("Init MyAction -- target: {}", context.getTarget().getId());
            }
        };
    }

    @Bean
    public Action<String, String> s1Action() {
        return new Action<String, String>() {
            public void execute(StateContext<String, String> context) {
                LOGGER.info("S1 MyAction -- target: {}", context.getTarget().getId());
            }
        };
    }

    private Action<String, String> s2Action() {
        return new Action<String, String>() {
            @Override
            public void execute(StateContext<String, String> context) {
                LOGGER.info("S2 MyAction -- target: {}", context.getTarget().getId());
            }
        };
    }

    // 通过Bean注解装配其他bean的属性
    @Bean
    public StateMachineContext stateMachineContext(
            @Qualifier("stateMachine") StateMachine stateMachine,
            @Qualifier("stateMachineListener") StateMachineListener stateMachineListener) {
        // 设置状态机监听器
        stateMachine.addStateListener(stateMachineListener);
        return new StateMachineContext(stateMachine);
    }
}
// StateMachineContext.java
// 这个类的定义不是必须的,存粹是为了方便通过@Bean注解方式配置状态机监听器StateMachineListener
public class StateMachineContext {
    private StateMachine stateMachine;

    public StateMachineContext(StateMachine stateMachine) {
        this.stateMachine = stateMachine;
    }

    public StateMachine getStateMachine() {
        return stateMachine;
    }

    public void setStateMachine(StateMachine stateMachine) {
        this.stateMachine = stateMachine;
    }
}
// 状态机监听器
@Component
public class StateMachineListener extends StateMachineListenerAdapter<String, String> {
    private static final Logger LOGGER = LoggerFactory.getLogger(StateMachineListener.class);
    @Override
    public void stateChanged(State<String, String> from, State<String, String> to) {
        LOGGER.info("Transitioned from {} to {}", from == null ? "none" : from.getId(), to.getId());
    }
}

Spring StateMachine使用示例:

public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.chench.extra.java.statemachine.spring"); // 设置状态机相关配置及组件所在的包名
        context.refresh();

        // 从Spring容器中获取状态机实例
        StateMachine<String, String> stateMachine = context.getBean(StateMachine.class);

        // 开启状态机
        stateMachine.startReactively().block();

        // 事件操作,触发状态机内部的状态转换
        Message<String> messageE1 = MessageBuilder.withPayload("E1").build();
        stateMachine.sendEvent(Mono.just(messageE1)).blockLast();

        Message<String> messageE2 = MessageBuilder.withPayload("E2").build();
        stateMachine.sendEvent(Mono.just(messageE2)).blockLast();

        Message<String> messageE3 = MessageBuilder.withPayload("E3").build();
        stateMachine.sendEvent(Mono.just(messageE3)).blockLast();

        // 停止状态机
        stateMachine.stopReactively().block();
    }
}

输出信息如下:

Transitioned from none to SS -- 状态机进入初始状态
Init MyAction -- target: S1  -- 状态机从SS状态转换到S1状态执行的动作
Transitioned from SS to S1   -- 状态机从SS状态转换到S1状态
S1 MyAction -- target: S2    -- 状态机从S1状态转换到S2状态执行的动作
Transitioned from S1 to S2   -- 状态机从S1状态转换到S2状态
S2 MyAction -- target: SF    -- 状态机从S2状态转换到SF状态执行的动作
Transitioned from S2 to SF   -- 状态机从S2状态转换到SF状态

Cola状态机

Cola状态机的使用和配置比Spring StateMachine简单直接,以电商场景的订单状态转换为例进行阐述。
设计订单状态及其转化图如下:
Cola_订单状态转换

添加依赖:

<!-- cola-component-statemachine -->
<dependency>
    <groupId>com.alibaba.cola</groupId>
    <artifactId>cola-component-statemachine</artifactId>
    <version>4.3.2</version>
</dependency>

分别定义订单状态,订单事件,订单上下文。

// 订单状态
public enum OrderStatus {
    INIT("初始化", 0),
    PAY_ONLINE("待支付", 1),
    WAITING_FOR_RECEIVED("待接单", 2),
    WAITING_DELIVERY("待发货", 3),
    PART_DELIVERY("部分发货", 4),
    ALL_DELIVERY("全部发货", 5),
    DELIVER_ALL("待收货", 6),
    RECEIVED("已收货", 7),
    DONE("已完成", 8),
    CANCEL("已关闭", 9);

    private String name;
    private int code;
    OrderStatus(String name, int code) {
        this.name = name;
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public int getCode() {
        return code;
    }
}
// 订单事件
public enum OrderEvent {
    CREATE_ORDER(1, "创建订单"),
    REPAY(2, "支付"),
    CANCEL_ORDER(3, "取消订单"),
    TAKE_ORDER(4, "接单"),
    REJECT_ORDER(5, "拒单"),
    DELIVERY_PART(6, "部分发货"),
    DELIVERY_ALL(7, "全部发货"),
    CONFIRM_RECEIPT(8, "确认收货"),
    EXTEND_RECEIPT(9, "延长收货"),
    COMPLETE(10, "交易完成");

    private int code;
    private String name;
    OrderEvent(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public String getName() {
        return name;
    }
}
// 订单上下文
public class OrderContext {
    private String orderId;

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}

使用Cola状态机:

public class ColaStateMachineSample {
    // 状态机实例
    static StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine;

    public static void main(String[] args) {
        // 状态机构建器
        StateMachineBuilder<OrderStatus, OrderEvent, OrderContext> builder = StateMachineBuilderFactory.create();

        // 设置订单状态转换路径
        // 初始化 -> 待支付
        builder.externalTransition()
                .from(OrderStatus.INIT)
                .to(OrderStatus.PAY_ONLINE)
                .on(OrderEvent.CREATE_ORDER)
                .perform(createOrderAction());

        // 待支付 -> 待接单
        builder.externalTransition()
                .from(OrderStatus.PAY_ONLINE)
                .to(OrderStatus.WAITING_FOR_RECEIVED)
                .on(OrderEvent.REPAY)
                .perform(waitingOrderAction());

        // 待接单 -> 待发货
        builder.externalTransition()
                .from(OrderStatus.WAITING_FOR_RECEIVED)
                .to(OrderStatus.WAITING_DELIVERY)
                .on(OrderEvent.TAKE_ORDER)
                .perform(takeOrderAction());

        // 待发货 -> 部分发货
        builder.externalTransition()
                 .from(OrderStatus.WAITING_DELIVERY)
                 .to(OrderStatus.PART_DELIVERY)
                 .on(OrderEvent.DELIVERY_PART)
                 .perform(deliverPartOrderAction());

        // 部分发货 -> 部分发货 :内部转换
        builder.internalTransition()
                .within(OrderStatus.PART_DELIVERY)
                .on(OrderEvent.DELIVERY_PART)
                .when(checkOrder())
                .perform(deliverPartOrderAction());

        // 部分发货 -> 全部发货
        builder.externalTransition()
                .from(OrderStatus.PART_DELIVERY)
                .to(OrderStatus.ALL_DELIVERY)
                .on(OrderEvent.DELIVERY_ALL)
                .perform(deliverAllOrderAction());

        // 待发货 -> 全部发货
        builder.externalTransition()
                .from(OrderStatus.WAITING_DELIVERY)
                .to(OrderStatus.ALL_DELIVERY)
                .on(OrderEvent.DELIVERY_ALL)
                .perform(deliverAllOrderAction());

        // 全部发货 -> 待收货
        builder.externalTransition()
                .from(OrderStatus.ALL_DELIVERY)
                .to(OrderStatus.DELIVER_ALL)
                .on(OrderEvent.DELIVERY_ALL)
                .perform(receiveConfirmOrderAction());

        // 待收货 -> 已收货
        builder.externalTransition()
                .from(OrderStatus.DELIVER_ALL)
                .to(OrderStatus.RECEIVED)
                .on(OrderEvent.CONFIRM_RECEIPT)
                .perform(receivedOrderAction());

        // 待支付,待接单,待发货,待收货 -> 已关闭
        builder.externalTransitions()
                .fromAmong(OrderStatus.PAY_ONLINE, OrderStatus.WAITING_FOR_RECEIVED, OrderStatus.WAITING_DELIVERY, OrderStatus.DELIVER_ALL)
                .to(OrderStatus.CANCEL)
                .on(OrderEvent.CANCEL_ORDER)
                .perform(cancelOrderAction());

        // 已收货 -> 已完成
        builder.externalTransition()
                .from(OrderStatus.RECEIVED)
                .to(OrderStatus.DONE)
                .on(OrderEvent.COMPLETE)
                .perform(doneOrderAction());

        // 构建状态机实例
        stateMachine = builder.build("ColaStateMachineSample");

        // 触发创建订单事件,状态转换:“初始化” -> “待支付”
        stateMachine.fireEvent(OrderStatus.INIT, OrderEvent.CREATE_ORDER, new OrderContext());
    }

    // 创建订单
    private static Action<OrderStatus, OrderEvent, OrderContext> createOrderAction() {
        return (from, to, event, context) -> {
            System.out.println("创建订单");
            // 1.获取状态机
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();
            // 2.组装订单上下文
            OrderContext orderContext = getOrderContext();
            // 3.触发状态机事件
            stateMachine.fireEvent(OrderStatus.PAY_ONLINE, OrderEvent.REPAY, orderContext);
        };
    }

    // 待接单
    private static Action<OrderStatus, OrderEvent, OrderContext> waitingOrderAction() {
        return (from, to, event, context) -> {
            System.out.println("待接单");

            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();
            stateMachine.fireEvent(OrderStatus.WAITING_FOR_RECEIVED, OrderEvent.TAKE_ORDER, getOrderContext());
        };
    }

    // 待发货
    private static Action<OrderStatus, OrderEvent, OrderContext> takeOrderAction() {
        return (from, to, event, context) -> {
            System.out.println("待发货");
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();

            // 检查是否全部发货
            int r = new Random().nextInt(10);
            if (r % 3 == 0) {
                // 全部发货
                stateMachine.fireEvent(OrderStatus.WAITING_DELIVERY, OrderEvent.DELIVERY_ALL, getOrderContext());
            } else {
                // 部分发货
                stateMachine.fireEvent(OrderStatus.WAITING_DELIVERY, OrderEvent.DELIVERY_PART, getOrderContext());
            }
        };
    }

    // 部分发货
    private static Action<OrderStatus, OrderEvent, OrderContext> deliverPartOrderAction() {
        return (from, to, event, context) ->  {
            System.out.println("部分发货");
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();

            // 检查是否还是部分发货
            int r = new Random().nextInt(10);
            if (r % 2 == 0) {
                // 还是部分发货
                stateMachine.fireEvent(OrderStatus.PART_DELIVERY, OrderEvent.DELIVERY_PART, getOrderContext());
            } else {
                // 全部发货
                stateMachine.fireEvent(OrderStatus.PART_DELIVERY, OrderEvent.DELIVERY_ALL, getOrderContext());
            }
        };
    }

    // 检查订单状态
    private static Condition<OrderContext> checkOrder() {
        return new Condition<OrderContext>() {
            @Override
            public boolean isSatisfied(OrderContext context) {
                return true;
            }
        };
    }

    // 全部发货
    private static Action<OrderStatus, OrderEvent, OrderContext> deliverAllOrderAction() {
        return ((from, to, event, context) -> {
            System.out.println("全部发货");
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();
            stateMachine.fireEvent(OrderStatus.ALL_DELIVERY, OrderEvent.DELIVERY_ALL, getOrderContext());
        });
    }

    // 待收货
    private static Action<OrderStatus, OrderEvent, OrderContext> receiveConfirmOrderAction() {
        return ((from, to, event, context) -> {
            System.out.println("待收货");
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();
            stateMachine.fireEvent(OrderStatus.DELIVER_ALL, OrderEvent.CONFIRM_RECEIPT, getOrderContext());
        });
    }

    // 已收货
    private static Action<OrderStatus, OrderEvent, OrderContext> receivedOrderAction() {
        return ((from, to, event, context) -> {
            System.out.println("已收货");
            StateMachine<OrderStatus, OrderEvent, OrderContext> stateMachine = getStateMachine();
            stateMachine.fireEvent(OrderStatus.RECEIVED, OrderEvent.COMPLETE, getOrderContext());
        });
    }

    // 已关闭
    private static Action<OrderStatus, OrderEvent, OrderContext> cancelOrderAction() {
        return ((from, to, event, context) -> {
            System.out.println("已关闭");
        });
    }

    // 已完成
    private static Action<OrderStatus, OrderEvent, OrderContext> doneOrderAction() {
        return ((from, to, event, context) -> {
            System.out.println("已完成");
        });
    }

    private static StateMachine<OrderStatus, OrderEvent, OrderContext> getStateMachine() {
        return stateMachine;
    }

    private static OrderContext getOrderContext() {
        return new OrderContext();
    }
}

输出:

创建订单
待接单
待发货
部分发货
全部发货
待收货
已收货
已完成

分布式事务框架SeataSAGA模式就是使用状态机机制实现的,但是其状态转换并非硬编码配置,而是通过状态机设计器进行编排最终导出为json格式文件,每一个分布式事务业务流程就对应一个编排文件。

【参考】
什么是状态机?一篇文章就够了
状态机的介绍和使用
状态机的技术选型看这篇就够了,最后一个直叫好!!!
全网首发:Seata Saga状态机设计器实战
如何将Saga建模为状态机
保姆式教程!如何使用Cola-statemachine构建高可靠性的状态机 ?
Cola-StateMachine状态机的实战使用

标签:DELIVERY,return,入门,stateMachine,实践,状态机,OrderStatus,public
From: https://www.cnblogs.com/nuccch/p/18104658

相关文章

  • 【QT入门】 QListWidget各种常见用法详解之图标模式
    往期回顾【QT入门】Qt代码创建布局之多重布局变换与布局删除技巧-CSDN博客【QT入门】QTabWidget各种常见用法详解-CSDN博客【QT入门】QListWidget各种常见用法详解之列表模式-CSDN博客【QT入门】QListWidget各种常见用法详解之图标模式QListWidget有列表和图标两种......
  • 【QT入门】 QTabWidget各种常见用法详解
    往期回顾:【QT入门】Qt代码创建布局之分裂器布局详解-CSDN博客【QT入门】Qt代码创建布局之setLayout使用-CSDN博客【QT入门】Qt代码创建布局之多重布局变换与布局删除技巧-CSDN博客 【QT入门】QTabWidget各种常见用法详解一般来说,学一个新的控件,首先要看他是怎么构......
  • 物联网实战--入门篇之(二)环境准备
    目录一、硬件清单二、开发工具三、嵌入式环境搭建四、硬件连接(断电操作)五、服务器搭建六、Qt开发环境搭建一、硬件清单        巧妇难为无米之炊,要想学习制作这么一个净化器需要购买必要的硬件设备,以下是清单,根据链接自行采购,总价也就60RMB左右,不会很高。......
  • Typescript 入门
    ts是什么TS是TypeScript的缩写,由微软开发的一种开源的编程语言以前官网说“ts是js超级”,现在改为: TypeScript是具有类型语法的JavaScript。目前TypeScript5.4已经发布(2024-03)—— ts官网Tip:ts缺点:开发更费麻烦,要多写东西了,看个人取舍。环境基于笔者博文《vue3入......
  • Python数据库编程全指南SQLite和MySQL实践
    1.安装必要的库首先,我们需要安装Python的数据库驱动程序,以便与SQLite和MySQL进行交互。对于SQLite,Python自带了支持;而对于MySQL,我们需要安装额外的库,如mysql-connector-python。#安装MySQL连接器pipinstallmysql-connector-python2.连接SQLite数据库SQLite是一......
  • 客快物流大数据项目(七十):Impala入门介绍 一般有用 看1
    Impala入门介绍一、impala基本介绍impala是cloudera提供的一款高效率的sql查询工具,提供实时的查询效果,官方测试性能比hive快10到100倍,其sql查询比sparkSQL还要更加快速,号称是当前大数据领域最快的查询sql工具,impala是参照谷歌的新三篇论文(Caffeine--网络搜索引擎、Pregel--分布......
  • Celery快速入门的教程
    1、快速入门1.1、config.py【redis和rabbitmq配置代码】fromceleryimportCelerybroker='amqp://celery:[email protected]:5672/celery_host'#rabbitMQbackend='redis://:[email protected]:6379/2'#redis地址#1实例化得到celery对象app=Celer......
  • 2.java openCV4.x 入门-hello OpenCV
    专栏简介......
  • 前端 Typescript 入门
    前端Typescript入门Antdesignvue4.x基于vue3,示例默认是TypeScript。比如table组件管理。vue3官网介绍也使用了TypeScript,例如:响应式API:核心华为的鸿蒙OS(HarmonyOS)开发中也可以使用TypeScript本篇目的用于对TS进行扫盲Tip:ts路线图ts是什么TS是TypeScript的......
  • C++从入门到精通——函数重载
    函数重载前言一、函数重载概念二、函数重载的分类参数类型不同的函数重载参数个数不同的函数重载参数类型顺序不同的函数重载三、函数重载的具体代码展示main.cpp四、为什么为什么C++支持函数重载,而C语言不支持函数重载呢前言函数重载是指在同一个作用域内,可以定......