Java状态机
目录
1. 概念
2. 定义状态机
3. 生成一个状态机
4. 使用
1. 概念
在Java的应用开发里面,应该会有不少的人接触到一个业务场景下,一个数据的状态会发生多种变化,最经典的例子例如订单,当然还有像用户的状态变化(冻结,销户等),文章的状态变化(已发布,草稿等)。像这些具有多种状态的事物,如果我们不进行一些措施来进行维护和扩展的话,那么将会导致状态越难越难以管理,而且对状态的转变也会越来越难以定义。
那么讲出了它现在存在的问题,也就能大概知道本文要讲的是主要内容是什么了。没错,状态机就是用来规范使用状态的各种变化的一种产物。
可能大家还不清楚这个玩意为什么产生,我给大家一个场景,如果没有一种严格的状态机控制,那么像订单这种,我们是不是可以直接从已下单的状态直接推进到已发货的状态,而越过中间的支付等等的中间状态。这显然是有问题的。
在状态机当中,具有四个概念,用来控制状态的变化。一种状态需要迁移到下一种状态,一定是经过某种行为或者事件转化到下一个状态。所以这也就成为了状态机的核心概念。
-
状态(States):代表系统可能处于的各种状态,例如 "已下单"、"已支付"、"已发货" 等。
-
事件(Events):触发状态转换的事件,例如 "下单"、"支付"、"发货" 等。
-
动作(Actions):在状态转换发生时执行的操作或行为。
-
转换(Transitions):定义状态之间的转换规则,即在某个事件发生时,系统从一个状态转换到另一个状态的规则
2. 定义状态机
我们可以定义一个状态机,并声明两个变量,一个用来记录状态变化的记录,一个用来记录要经过下一个状态需要的源状态与事件。在生成一个状态机的过程,我们将记录他需要变化的所有的状态,事件以及转换。
public class StateMachine {private Map<String,String> translatedTransitionsMap = new HashMap<>();private Set<String> translatedTransitions = new HashSet<>();private static final String DEFAULT_DELIMITER = "->";public StateMachine(Transition[] transitions){for (Transition transition : transitions) {translatedTransitions.add(transition.getFrom() + DEFAULT_DELIMITER +transition.getEvent() + DEFAULT_DELIMITER+ transition.getTo());if(translatedTransitionsMap.containsKey(transition.getFrom() + DEFAULT_DELIMITER + transition.getEvent())){throw new RuntimeException("Duplicate transition found: " +transition.getFrom() +DEFAULT_DELIMITER +transition.getAction());}translatedTransitionsMap.put(transition.getFrom() + DEFAULT_DELIMITER + transition.getEvent(),transition.getTo());}}public String getNextState(String from, String event){return translatedTransitionsMap.get(from + DEFAULT_DELIMITER + event);}public boolean checkTransitions(String from, String even){return translatedTransitions.contains(from + DEFAULT_DELIMITER + event);}}
过渡类的内容为
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Transition {/*** 起始状态*/private String from;/*** 动作*/private String even;/*** 目标状态*/private String to;}
3. 生成一个状态机
我们此次以订单举例,生成一个订单的状态机
public class OrderStatusModel {private static StateMachine ORDEER_STATEMACHINE;static {ORDEER_STATEMACHINE = new StateMachine(new Transition[]{new Transition(TradeStatusEnum.NEW.getStatus(), TradeEventEnum.CONFIRM.name(), TradeStatusEnum.WAIT_PAY.getStatus()),new Transition(TradeStatusEnum.NEW.getStatus(), TradeEventEnum.CANCEL.name(), TradeStatusEnum.CLOSED.getStatus()),new Transition(TradeStatusEnum.WAIT_PAY.getStatus(), TradeEventEnum.PAY.name(), TradeStatusEnum.PAY_SUCCESS.getStatus()),new Transition(TradeStatusEnum.WAIT_PAY.getStatus(), TradeEventEnum.PAY_CANCEL.name(), TradeStatusEnum.CANCELLED.getStatus()),new Transition(TradeStatusEnum.PAY_SUCCESS.getStatus(), TradeEventEnum.CONFIRM_SUCCESS.name(), TradeStatusEnum.COMPLETED.getStatus())});}public static String getTargetStatus(TradeStatusEnum currentStatus, TradeEventEnum tradeEventEnum) {return ORDEER_STATEMACHINE.getNextState(currentStatus.getStatus(), tradeEventEnum.name());}}
订单状态枚举
@Getter
public enum TradeStatusEnum {/*** 新建订单*/NEW("NEW", "新建订单"),/*** 锁单成功-待支付状态*/WAIT_PAY("WAIT_PAY", "待支付"),/*** 支付成功*/PAY_SUCCESS("PAY_SUCCESS", "支付成功"),/*** 已完成*/COMPLETED("COMPLETED","已完成"),/*** 已取消*/CANCELLED("CANCELLED","已取消"),/*** 订单关闭*/CLOSED("CLOSED","订单关闭");private String status;private String desc;TradeStatusEnum(String status, String desc) {this.status = status;this.desc = desc;}
}
订单事件
public enum TradeEventEnum {/*** 订单确认*/CONFIRM,/*** 取消订单*/CANCEL,/*** 支付*/PAY,/*** 支付取消*/PAY_CANCEL,/*** 订单确认成功*/CONFIRM_SUCCESS,/*** 订单完成*/FINISH
}
4. 使用
@Data
public class TradeOrder {private String orderId;private String status;private double price;public TradeOrder confirm(TradeCreateRequest request) {this.setStatus(OrderStatusModel.getTargetStatus(request.getTradeStatus(), TradeEventEnum.CONFIRM));return this;}public TradeOrder pay(TradeWaitPayRequest request) {this.setStatus(OrderStatusModel.getTargetStatus(request.getTradeStatus(), TradeEventEnum.CANCEL));return this;}
}
传参为
public class TradeCreateRequest extends BaseResquest{@Overridepublic TradeStatusEnum getTradeStatus(){return TradeStatusEnum.NEW;}
}
public abstract class BaseResquest {abstract TradeStatusEnum getTradeStatus();
}
相关文章:
Java状态机
目录 1. 概念 2. 定义状态机 3. 生成一个状态机 4. 使用 1. 概念 在Java的应用开发里面,应该会有不少的人接触到一个业务场景下,一个数据的状态会发生多种变化,最经典的例子例如订单,当然还有像用户的状态变化(冻结…...
【Pandas】pandas Series isin
Pandas2.2 Series Computations descriptive stats 方法描述Series.align(other[, join, axis, level, …])用于将两个 Series 对齐,使其具有相同的索引Series.case_when(caselist)用于根据条件列表对 Series 中的元素进行条件判断并返回相应的值Series.drop([lab…...

通过VSCode直接连接使用 GPT的编程助手
GPT的编程助手在VSC上可以直接使用 选择相应的版本都可以正常使用。每个月可以使用40条,超过限制要付费。 如下图对应的4o和claude3.5等模型都可以使用。VSC直接连接即可。 配置步骤如下: 安装VSCODE 直接,官网下载就行 https://code.vis…...

一种最常见的js加密解密
前言 在前端开发的广袤天地中,你是否遭遇过一些看似“乱码”般的代码,根本无从下手理解?这其实很可能是被 _0x处理过的代码。_0x就像一位神秘的“化妆师”,能把原本清晰的代码改头换面。今天,我就来分享如何破解这些被…...
【Python爬虫(4)】揭开Python爬虫的神秘面纱:基础概念全解析
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
SMOJ 一笔画/洛谷 P7171 COCI 2020/2021 #3 Selotejp 题解
1.一笔画 题意 给出 n 行 m 列的点阵,每个点是一个字符: “.” 或 “#” ,其中“#”表示该点是障碍物。 现在小毛的问题是: 他最少要画多少笔才能把点阵里所有的“.”都覆盖完毕(被小毛画到的点就会被覆盖ÿ…...

【Java学习】继承
一、继承 子类继承父类,子类这个类变量的引用在原有的指向子类自己类变量空间的原有访问权限上,增加上了父类类变量空间的访问权限,此时子类类变量指向的空间变为了原来子类类变量空间加上父类类变量空间,此时子类类变量空间就变成…...

计时器任务实现(保存视频和图像)
下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每60秒保存一个视频,图像和视频均以当前时间命名: TimerTask类的实现如下: class TimerTask { public:TimerTask(const std::string& path):…...

树莓百度百科能否揭开成都树莓集团的神秘面纱?
树莓百度百科作为大众获取信息的重要渠道,在一定程度上为人们了解树莓集团提供了窗口,但要完全揭开其神秘面纱,仍存在一定局限性。 从树莓百度百科上,我们能获取到关于树莓集团的基本信息,如公司的成立时间、法定代表人…...

【如何看懂数据手册和原理图】
【如何看懂数据手册和原理图】 文章目录 【如何看懂数据手册和原理图】1.数据手册1.1去哪里看?1.2需要注意的 2.支路3.回路4.网孔5.电路定理:基尔霍夫定律**集总参数电路** 抽象理想化5.1基尔霍夫电流定律 (KCL)5.2基尔霍夫电压定律 (KVL)5.3总结 6.读懂…...

SQL 优化工具使用之 explain 详解
一、导读 对于大部分开发人员来说,平常接触的无非就是增删改查这些基本操作,创建存储过程,视图等等都是 DBA 该干的活,但是想要把这些基本操作写的近乎完美也是一件难事。 而 explain 显示了 MySQL 如何使用索引来处理 select 语…...
深度解析Unity3D渲染管线:网格、材质与GPU渲染的协同逻辑
在3D实时渲染领域,网格(Mesh)、材质(Material)和GPU渲染三者构成了虚拟世界的基石。它们如同乐高积木的零件,通过精确的协作,最终在屏幕上呈现出复杂的视觉场景。本文将从技术原理、协作机制到性…...

POI优化Excel录入
57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…...

实时图像与视频超分辨率:高效子像素卷积网络(ESPCN)解析
文章目录 概要理论知识操作实操环境配置基础命令格式:效果示例 概要 超分辨率系列论文阅读卷1:Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network PDF网址:https://arxiv.org/…...

QT--对话框的切换
文章目录 前言一、主窗口ui二、创建子窗口三、步骤1.主界面------>子页面2.子界面------>主页面 四、总结 前言 之前我们学了qt中最重要的东西–信号和槽 我们现在实现这样一个demo,程序启动后弹出主界面,点击主界面的按钮弹出子窗口,…...
深入浅出:CUDA是什么,如何利用它进行高效并行计算
在当今这个数据驱动的时代,计算能力的需求日益增加,特别是在深度学习、科学计算和图像处理等领域。为了满足这些需求,NVIDIA推出了CUDA(Compute Unified Device Architecture),这是一种并行计算平台和编程模…...

Zotero PDF Translate插件配置百度翻译api
Zotero PDF Translate插件可以使用几种翻译api,虽然谷歌最好用,但是由于众所周知的原因,不稳定。而cnki有字数限制,有道有时也不行。其他的翻译需要申请密钥。本文以百度为例,进行申请 官方有申请教程: Zot…...

利用acme.sh 申请 Google 免费证书
1.Google API权限准备 获取 EAB 密钥 ID 和 HMAC 登录你的 GCP 控制台面板,进入 Public Certificate Authority API 管理页面(https://console.cloud.google.com/apis/library/publicca.googleapis.com)点击启动: 或者直接在下一…...

腾讯云cloudstudio使用笔记(一)
0、计划及目标 1)、这个系列用于将cloudstudio快速入门将前端代码在cloudstudio中从git仓库拉下来并运行—本文档的目标已实现 2)、基于cloudstudio和腾讯的ai代码助手腾讯自己满血的deepseek写代码,减少前端工作量—待补充 3)、…...

python自动化制作常规的日报数据可视化
python自动化制作常规的日报数据可视化 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏Ǵ…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...