【设计模式系列】状态模式(二十三)

news2024/12/12 19:58:26

一、什么是状态模式

状态模式(State Pattern)是一种行为设计模式,其核心目的是管理一个对象在其内部状态改变时的行为变化,其核心理念是将对象的行为和状态分离。这种模式通过将每个状态相关的行为封装在独立的类中,使得对象在不同状态下可以有不同的行为表现,而不需要在对象内部使用大量的条件判断语句。

二、状态模式的角色

  1. State(状态接口):定义一个接口,封装与Context的一个特定状态相关的行为。这个接口通常包含一个或多个方法,这些方法将在具体状态类中被实现,以定义不同状态下对象的行为。

  2. ConcreteState(具体状态):实现State接口的具体类,每个具体状态类实现State接口中定义的一个或多个方法,定义具体状态对应的行为。当状态变化时,Context对象将改变其状态对象的引用,从而改变对象的行为。

  3. Context(上下文):维护一个State类型的引用,这个引用指向当前状态对象,即Context当前的状态。Context定义了客户程序与状态对象交互的接口,同时负责在状态改变时更新其状态对象的引用。

  4. StateMachine(状态机)(可选):在一些实现中,可能存在一个单独的状态机角色,它负责管理Context对象的状态转换。状态机可以包含状态转换逻辑,以及触发状态转换的事件处理。

三、状态模式的典型应用

  • 工作流管理系统:在工作流管理系统中,状态模式可以用来表示和控制工作流程的不同阶段,如待审批、审批中、已批准、已完成等。

四、状态模式在Spring Statemachine中的应用

在Spring Statemachine中,状态模式的角色应用可以具体描述如下:

  1. 上下文(Context)角色:在Spring Statemachine中,上下文角色通常由状态机的上下文对象StateMachine来扮演。这个对象持有当前状态,并在状态转换发生时更新其状态。上下文对象提供了发送事件和查询状态的方法,是状态模式中与客户端交互的主要接口。

  2. 状态接口(State)角色:在Spring Statemachine中,状态接口角色由状态枚举OrderStatus来实现。这个枚举定义了所有可能的状态,每个枚举值对应一个具体的状态。这些状态是状态机可以处于的点。

  3. 具体状态(Concrete State)角色:在Spring Statemachine中,具体状态角色由状态机配置中的StateMachineStateConfigurer来定义。具体状态包含了状态机在该状态下应该执行的行为,如进入状态、退出状态时的动作,以及状态机在该状态下可以响应的事件。

  4. 事件(Event)角色:在Spring Statemachine中,事件角色由事件枚举OrderEvent来实现。这个枚举定义了所有可能触发状态转换的事件。当这些事件发生时,状态机可以根据配置进行状态转换。

以下是具体的代码示例,展示了这些角色如何在Spring Statemachine中应用:

// 状态枚举,扮演状态接口角色
public enum OrderStatus {
    CREATED, PAID, SHIPPED, COMPLETED
}

// 事件枚举,扮演事件角色
public enum OrderEvent {
    PAY, SHIP, COMPLETE
}

// 状态机配置,定义具体状态和状态转换
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderEvent> {

    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception {
        states
            .withStates()
                .initial(OrderStatus.CREATED)
                .state(OrderStatus.PAID)
                .state(OrderStatus.SHIPPED)
                .state(OrderStatus.COMPLETED);
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
        transitions
            .withExternal()
                .source(OrderStatus.CREATED).target(OrderStatus.PAID).event(OrderEvent.PAY)
            .and()
            .withExternal()
                .source(OrderStatus.PAID).target(OrderStatus.SHIPPED).event(OrderEvent.SHIP)
            .and()
            .withExternal()
                .source(OrderStatus.SHIPPED).target(OrderStatus.COMPLETED).event(OrderEvent.COMPLETE);
    }
}

// 状态机服务,扮演上下文角色
@Service
public class OrderService {
    private final StateMachine<OrderStatus, OrderEvent> stateMachine;

    @Autowired
    public OrderService(StateMachine<OrderStatus, OrderEvent> stateMachine) {
        this.stateMachine = stateMachine;
    }

    public void processPayment() {
        stateMachine.sendEvent(OrderEvent.PAY);
    }

    public void processShipping() {
        stateMachine.sendEvent(OrderEvent.SHIP);
    }

    public void processCompletion() {
        stateMachine.sendEvent(OrderEvent.COMPLETE);
    }
}

在这个示例中,OrderStatus枚举和OrderEvent枚举分别扮演了状态接口和事件的角色,而OrderService类中的stateMachine对象则扮演了上下文角色,负责根据事件触发状态转换。每个状态转换都对应于一个具体的状态,这些状态在状态机配置中被定义。这样,状态模式的逻辑就被嵌入到了Spring Statemachine的框架中,使得状态管理变得更加清晰和易于维护。

在客户端代码中,我们将创建OrderService的实例,并使用它来触发状态转换事件,同时打印当前的状态。

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderApplication implements CommandLineRunner {

    private final OrderService orderService;

    public OrderApplication(OrderService orderService) {
        this.orderService = orderService;
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @Override
    public void run(String... args) {
        // 初始状态
        System.out.println("Initial state: " + orderService.getCurrentState());

        // 处理支付事件,状态转换为PAID
        orderService.processPayment();
        System.out.println("State after payment: " + orderService.getCurrentState());

        // 处理发货事件,状态转换为SHIPPED
        orderService.processShipping();
        System.out.println("State after shipping: " + orderService.getCurrentState());

        // 处理完成事件,状态转换为COMPLETED
        orderService.processCompletion();
        System.out.println("State after completion: " + orderService.getCurrentState());
    }
}

在这个客户端代码中,我们实现了CommandLineRunner接口,这样我们就可以在Spring Boot应用启动后自动执行run方法。在run方法中,我们模拟了订单状态的转换过程,并在每个步骤后打印当前的状态。

这样,我们就完成了状态模式在Spring Statemachine中的应用,包括状态枚举、事件枚举、状态机配置、状态机服务以及客户端代码。这个示例展示了如何使用Spring Statemachine来管理状态和状态转换。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 LlamaFactory 结合开源大语言模型实现文本分类:从数据集构建到 LoRA 微调与推理评估

文章目录 背景介绍文本分类数据集Lora 微调模型部署与推理期待模型的输出结果 文本分类评估代码 背景介绍 本文将一步一步地&#xff0c;介绍如何使用llamafactory框架利用开源大语言模型完成文本分类的实验&#xff0c;以 LoRA微调 qwen/Qwen2.5-7B-Instruct 为例。 文本分类…

AI大模型赋能医学诊疗与药学服务——课题基金申请辅导项目成功举办

2024年11月23日&#xff0c;北京整合医学学会在线上成功举办了“AI大模型赋能医学诊疗与药学服务——课题基金申请辅导项目”。此次会议吸引了来自全国各地的医学、药学及人工智能领域的专家学者和科研人员积极参与&#xff0c;共同探讨AI大模型在医学诊疗与药学服务中的应用&a…

Java8 CompletableFuture异步编程

文章目录 CompletableFuturede介绍CompletableFuturede使用场景常用异步编程实现方案- Thread- ExecutorService- CountDownLatch- CyclicBarrier- ForkJoinPool- CompletableFuture各种实现方案总结 CompletableFuturede结构结构梳理- Future接口- CompletionStage接口常用方法…

el-thee懒加载删除某条数据 ,el-thee懒加载重置,el-thee刷新某个节点

一、懒加载的tree已经全部展开&#xff0c;外部点击删除的时候不需要重新展开点击获取下一层数据 <template> <el-treeref"tree":data"treeData":props"defaultProps"render-after-expandhighlight-currentlazy:expand-on-click-node&q…

计算机网络-IPSec VPN工作原理

一、IPSec VPN工作原理 昨天我们大致了解了IPSec是什么&#xff0c;今天来学习下它的工作原理。 IPsec的基本工作流程如下&#xff1a; 通过IKE协商第一阶段协商出IKE SA。 使用IKE SA加密IKE协商第二阶段的报文&#xff0c;即IPsec SA。 使用IPsec SA加密数据。 IPsec基本工作…

国际荐酒师Peter助力第六届地博会,推动地理标志产品国际化发展

国际荐酒师Peter Lisicky助力第六届知交会暨地博会&#xff0c;推动地理标志产品国际化发展 第六届粤港澳大湾区知识产权交易博览会暨国际地理标志产品交易博览会于2024年12月9日至11日在中新广州知识城盛大举行&#xff0c;吸引了全球众多行业专家、企业代表及相关机构齐聚一…

Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件)

Android显示系统&#xff08;02&#xff09;- OpenGL ES - 概述 Android显示系统&#xff08;03&#xff09;- OpenGL ES - GLSurfaceView的使用 Android显示系统&#xff08;04&#xff09;- OpenGL ES - Shader绘制三角形 Android显示系统&#xff08;05&#xff09;- OpenGL…

【Golang】Go语言编程思想(六):Channel,第一节,介绍Channel

Channel 下面的几个例子将会展示如何定义一个 channel&#xff1a; func chanDemo() {var c chan int // chan int 的含义是, c 是一个 channel, 里面的内容是 int// 上面的声明语句将会创建一个 nil channel, c nil, 它的作用将在 select 当// 中体现 }创建一个非 nil 的 c…

怎么获取Java高并发经验与系统设计技能?

如何获得高并发经验&#xff1f; 这是系统邀请我回答的一个问题&#xff0c;由此也引发了我的一些思考&#xff1a;为什么人人都想要获得高并发经验&#xff1b;想拥有高并发系统设计技能&#xff1f; 其原因LZ认为主要有以下三点&#xff1a; 涨薪&#xff1a;有高并发系统设…

Spherical Harmonics (SH)球谐函数的原理及应用【3DGS】

Spherical Harmonics &#xff08;SH&#xff09;球谐函数的原理及应用【3DGS】 前言球谐函数&#xff08;Spherical Harmonics, SH&#xff09;球谐函数不同阶的表达式以及有什么不同&#xff1f;具体介绍球谐函数基函数球谐函数 前言 高斯泼溅Gaussian Splatting (GS) GS 模…

Java版-图论-拓扑排序与有向无环图

拓扑排序 拓扑排序说明 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列…

如何在 Odoo18 视图中添加关联数据看板按钮 | 免费开源ERP实施诀窍

文 / 开源智造 Odoo亚太金牌服务 引言 关联数据看板按钮乃是 Odoo 当中的一项强效功能&#xff0c;它容许用户顺遂地访问相关记录&#xff0c;或者直接从模型的表单视图施行特定操作。它们为用户给予了对重要信息的疾速访问途径&#xff0c;并简化了工作流程&#xff0c;由此…

TCP客户端服务器端通信(线程池版)

1、什么是监听套接字&#xff0c;和UDP相比&#xff0c;TCP为什么文件描述符变多了&#xff1f; 在网络编程中&#xff0c;TCP和UDP是两种常见的传输协议&#xff0c;它们之间最大的不同之一在于连接的管理方式。为了更好地理解这个区别&#xff0c;我们可以用一个生动的比喻来…

【Linux】通过crond服务设置定时执行shell脚本,实际执行时间却延迟了8小时

一、问题描述 通过使用crond服务设置定时任务&#xff0c;在每天凌晨的2:00执行脚本&#xff0c;但检查结果时发现&#xff0c;实际执行时间却在上午10点。 检查shell脚本执行结果发现&#xff0c;实际执行脚本时间在上午10:00&#xff0c;延迟了8小时。 检查系统时间&#xf…

Git基础笔记

目录 1.Git 常用命令 2.Git 分支操作 3.远程仓库操作 Git 概述 Git 是一个免费的、开源的 分布式版本控制系统 &#xff0c;可以快速高效地处理从小型到大型的各种 项目 1.Git 常用命令 1.设置用户签名 git config --global user.name 用户名 2.设置用户签名 git config…

PADS系列:绘制RTL8306原理图的过程

大家好&#xff0c;我是山羊君Goat。 在所有相关的元件都被创建到了原理图库之后&#xff0c;就可以正式开始原理图的绘制了。不过绘制过程中也是会按照一定的顺序来进行的&#xff0c;这样可以达到事半功倍的效果。 首先就是主芯片的放置&#xff0c;这里有三个主芯片&#x…

GCP Case:MountKirk Games

游戏后端 根据游戏活动动态放大或缩小。 连接到托管的nos0l数据库服务。 运行定制的linux发行版。 游戏分析平台 根据游戏活动来扩大或缩小规模直接处理来自游戏服务器的传入数据。 处理由于移动网络缓慢而迟到的数据。 通过sql查询来访问至少10tb的历史数据 处理由用户…

OpenCV相机标定与3D重建(10)眼标定函数calibrateHandEye()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算手眼标定&#xff1a; g T c _{}^{g}\textrm{T}_c g​Tc​ cv::calibrateHandEye 是 OpenCV 中用于手眼标定的函数。该函数通过已知的机器人…

【CSS in Depth 2 精译_072】第 12 章 CSS 排版与间距概述 + 12.1 间距设置(上):究竟该用 em 还是 px

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 ✔️ 12.1.1 使用 em 还是 px ✔️12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 文章目录 第 12 章 排版与间距…

数据结构代码归纳

1.线性表 线性表的顺序表示 定义与初始化 typedef struct SqList{ElemType data[MaxSize];//ElemType *data 开动态数组 int length; }Sqlist; void InitList(SqList &L){L.length0;//若静态数组//若动态数组 //L.data(ElemType*)malloc(sizeof(ElemType)*MaxSize); }…