Java状态模式源码剖析及使用场景

状态模式

  • 一、介绍
  • 二、订单处理系统中使用
  • 三、Spring 中事务怎么使用状态模式?

一、介绍

状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

状态模式的核心思想是将对象的状态封装成独立的类,使得对象可以根据自身的状态来获取不同的行为。当对象的内部状态发生改变时,其行为也会随之改变。

状态模式的主要角色有:

  1. Context(上下文): 定义客户感兴趣的接口,并维护一个具体状态类的实例。

  2. State(状态): 这是一个抽象状态类,它定义了一个与Context的一个或多个行为相关的接口。

  3. ConcreteState(具体状态): 实现了抽象状态类所对应的行为。每一个子类实现对应于Context的一种状态。

状态模式的优点:

  1. 解耦了状态和行为,将它们分布到不同的类中,使得状态的改变不会影响行为的改变,行为的改变也不会影响状态的改变。
  2. 每种状态都可以根据自身的特点执行业务逻辑,因为每种状态对应一个子类。
  3. 支持对象状态的切换。
  4. 方便进行扩展,由于状态和行为是分开的,所以可以很方便地添加新的状态和行为。

状态模式的缺点:

  1. 会导致系统中类的个数增多。
  2. 在使用的过程中,需要分清系统中的每一种状态所对应的行为,以免产生错误。

状态模式的应用场景:

  1. 行为随状态改变而改变的场景。
  2. 一个操作中含有大量分支语句时,可以使用状态模式来把相关的分支语句转移到各个状态中。
  3. 处理订单流程、用户状态管理等领域都可以使用状态模式。

二、订单处理系统中使用

需求:一个简单的订单处理系统,订单从下单开始,经过多个状态的转换,最终到达完成状态。订单可能存在的状态包括:已下单(OrderedState)、已付款(PaidState)、已发货(ShippedState)、已签收(ReceivedState)、已完成(CompletedState)。当订单处于不同状态时,对应的操作也不同,比如在已下单状态下可以支付订单,在已付款状态下可以发货,以此类推。

// 订单状态接口,定义订单可执行的操作,如支付、发货、签收、完成等
interface OrderState {void pay();void ship();void receive();void complete();
}// 已下单状态,实现了订单OrderState在不同状态下的具体行为。
class OrderedState implements OrderState {private Order order;public OrderedState(Order order) {this.order = order;}@Overridepublic void pay() {System.out.println("已支付订单 " + order.getOrderId());order.setState(new PaidState(order));}@Overridepublic void ship() {System.out.println("订单尚未支付,无法发货");}@Overridepublic void receive() {System.out.println("订单尚未发货,无法签收");}@Overridepublic void complete() {System.out.println("订单尚未发货,无法完成");}
}// 已付款状态
class PaidState implements OrderState {private Order order;public PaidState(Order order) {this.order = order;}@Overridepublic void pay() {System.out.println("订单已经支付,无需重复支付");}@Overridepublic void ship() {System.out.println("正在发货订单 " + order.getOrderId());order.setState(new ShippedState(order));}@Overridepublic void receive() {System.out.println("订单尚未发货,无法签收");}@Overridepublic void complete() {System.out.println("订单尚未发货,无法完成");}
}// 其他状态类实现...// 订单上下文,它维护了订单的当前状态,并提供了相应的操作方法。这些方法内部会委托给当前状态对象执行具体的操作。
class Order {private String orderId;private OrderState state;public Order(String orderId) {this.orderId = orderId;this.state = new OrderedState(this); // 初始状态为已下单}public void pay() {state.pay();}public void ship() {state.ship();}public void receive() {state.receive();}public void complete() {state.complete();}public String getOrderId() {return orderId;}//改变订单的当前状态public void setState(OrderState state) {this.state = state;}
}// 客户端代码
public class Client {public static void main(String[] args) {Order order = new Order("1001");order.pay(); // 已支付订单 1001order.ship(); // 正在发货订单 1001order.receive(); // 已签收订单 1001order.complete(); // 订单已完成}
}
  1. OrderState 接口定义了订单可执行的操作,如支付、发货、签收、完成等。
  2. OrderedStatePaidStateShippedStateReceivedStateCompletedState 分别实现了订单在不同状态下的具体行为。
  3. Order 类是状态模式的上下文,它维护了订单的当前状态,并提供了相应的操作方法,如 pay()ship() 等。这些方法内部会委托给当前状态对象执行具体的操作。
  4. Order 类的 setState() 方法用于改变订单的当前状态。
  5. 在客户端代码中,我们创建了一个订单对象,然后依次调用支付、发货、签收、完成操作,订单状态会随着操作的执行而发生改变。

通过状态模式的实现,将订单的不同状态和行为分离开来,使得订单在状态改变时可以自动切换行为,提高了代码的可扩展性和可维护性。同时,由于每个状态对应一个子类,我们也可以很方便地添加新的状态和行为,满足未来需求的变化。

三、Spring 中事务怎么使用状态模式?

在 Spring 事务管理中,TransactionDefinition 接口定义了事务的各种属性,比如传播行为、隔离级别、超时时间等。而 TransactionStatus 接口则表示事务的不同状态,它是一个标记接口,具体的状态由其实现类 DefaultTransactionStatus 来维护。

DefaultTransactionStatus 内部使用一个 State 枚举来表示事务的不同状态,包括以下几种:

private enum State {ACTIVE,COMMITTED,ROLLED_BACK,COMMITTED_AFTER_ROLLBACK,ROLLBACK_AFTER_COMMITTED
}
  • ACTIVE: 事务处于活动状态
  • COMMITTED: 事务已提交
  • ROLLED_BACK: 事务已回滚
  • COMMITTED_AFTER_ROLLBACK: 事务在回滚后又被提交
  • ROLLBACK_AFTER_COMMITTED: 事务在提交后又被回滚

DefaultTransactionStatus 实现了 TransactionStatus 接口中的方法,根据当前的状态执行相应的操作。例如 setRollbackOnly() 方法用于标记事务需要回滚

public void setRollbackOnly() {switch (this.state) {case ACTIVE:setState(State.ROLLED_BACK);break;case COMMITTED:setState(State.ROLLBACK_AFTER_COMMITTED);break;case ROLLED_BACK:// Do nothingbreak;case COMMITTED_AFTER_ROLLBACK:setState(State.ROLLBACK_AFTER_COMMITTED);break;case ROLLBACK_AFTER_COMMITTED:// Do nothingbreak;default:throw new IllegalStateException("Invalid state transition attempted");}
}

这段代码根据当前事务的状态执行不同的操作。如果事务处于 ACTIVE 状态,则将其标记为 ROLLED_BACK。如果事务已经提交,则将其标记为 ROLLBACK_AFTER_COMMITTED 等。

另外,Spring 还提供了 TransactionSynchronization 接口,用于在事务生命周期的不同阶段执行特定的逻辑。AbstractPlatformTransactionManager 类中的 invokeAfterCommitinvokeAfterRollback 方法就会根据事务的当前状态决定是否调用相应的同步回调方法

protected void invokeAfterCommit(DefaultTransactionStatus status) {if (status.getState() == DefaultTransactionStatus.State.COMMITTED_AFTER_ROLLBACK) {invokeAfterRollbackHandlers(status);}invokeAfterCommitHandlers(status);
}protected void invokeAfterRollback(DefaultTransactionStatus status) {if (status.getState() == DefaultTransactionStatus.State.ROLLBACK_AFTER_COMMITTED) {invokeAfterCommitHandlers(status);}invokeAfterRollbackHandlers(status);
}

这些方法会根据事务的状态决定是先执行 commit 回调还是 rollback 回调,或者两者都执行。

看到 Spring 在处理事务管理时,使用了状态模式来封装事务的不同状态,并根据状态的变化执行相应的操作。这种设计使得事务管理的代码更加清晰、灵活和可扩展。如果需要添加新的状态或行为,只需要修改 State 枚举和相关方法,而不会影响整个事务管理框架的其他部分。

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

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

相关文章

深度学习Top10算法

自2006年深度学习概念被提出以来,20年快过去了,深度学习作为人工智能领域的一场革命,已经催生了许多具有影响力的算法。以下是深度学习top10算法,它们在创新性、应用价值和影响力方面都具有重要的地位。 1、深度神经网络&#xf…

鸿蒙开发(四)-低代码开发

鸿蒙开发(四)-低代码开发 本文主要介绍下鸿蒙下的低代码开发。 鸿蒙低代码是指在鸿蒙操作系统进行应用开发时,采用简化开发流程和减少编码量的方式来提高开发效率。 1:开启低代码开发 首先我们打开DevEco Studio .然后创建工程。 如图所示&#xff…

定制红酒:如何根据客户需求调整红酒口感与风格

在云仓酒庄洒派,云仓酒庄洒派深知不同消费者对于红酒的口感与风格有着不同的喜好和需求。因此,云仓酒庄洒派根据消费者的具体要求,灵活调整红酒的口感与风格,以满足他们的期望。 首先,云仓酒庄洒派会与消费者进行深入的…

AHU 汇编 实验三

实验名称:实验三 串操作指令 二、实验内容: 在数据段定义缓冲区,从键盘接收两串字符到两个缓冲区,将第二串中与第一串字符不一致的字符显示在屏幕。 实验过程: 源代码: data segmentmess1 db 16,?,16…

XGB-19:Xgboost常见问题QA

常见问题解答 本文档包含关于XGBoost的常见问题。 如何调整参数 请参阅参数调整指南。 模型描述 请参阅提升树介绍。 大数据集 XGBoost被设计为内存高效。通常,只要数据适合本机内存,它就可以处理问题。这通常意味着数百万个实例。 如果内存不足&…

数据分析-Pandas如何画图验证数据随机性

数据分析-Pandas如何画图验证数据随机性 数据分析和处理中,难免会遇到各种数据,那么数据呈现怎样的规律呢?不管金融数据,风控数据,营销数据等等,莫不如此。如何通过图示展示数据的规律? 数据表…

【字典合集】SecLists-更全面的渗透测试字典 v2024.1

下路路径 SecLists-更全面的渗透测试字典 v2024.1 简介 SecLists 是一个致力于收集各种安全字典的开源项目。这些字典包括但不限于:密码字典、用户名字典、网络扫描结果、漏洞利用载荷、web shells、可用于渗透测试的Payloads、以及其他各种安全相关的字典。 这…

Docker初体验之安装部署和镜像加速(openeuler版)

安装部署: 本人使用的为openeuler版本,无法使用二进制进行安装(使用二进制安装时,无法使用docker中的补全命令,需要重新进行配置)在此使用yum直接进行安装。 [rootlocalhost ~]# yum install docker 镜像…

如何远程SSH连接在家的服务器主机

当您需要通过SSH远程连接到家里的服务器主机时,以下是更详细的实施步骤: 1. 确保服务器主机已开启SSH服务 安装SSH服务:首先,确保您的服务器主机上安装了SSH服务。根据您的操作系统,您可以使用相应的包管理器来安装。…

LeetCode 174.地下城游戏 Python题解

地下城游戏 # 地下城游戏 """ 恶魔们抓住了公主并将她关在了地下城dungeon的右下角。地下城是由mxn个房间组成的二维网格。我们英勇的骑士最初被安置在左上角的房间里, 他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数…

在VMvare中虚拟机安装centos7和初始设置

下载镜像 阿里云的镜像站:https://mirrors.aliyun.com/centos/7/isos/x86_64/ 创建虚拟机过程 虚拟机创建过程比较简单,以下在VMvare16中进行安装 点击左上角,文件-新建虚拟机: 选择典型 选择刚刚下载好的镜像 输入虚拟机…

如何判断DNS解析故障?

DNS解析负责将域名解析到对应的IP地址,从而实现用户通过域名访问站点的效果。因此DNS解析是整个互联网中非常关键和基础的一个环节,但也是众多网站运营者和管理者经常忽视的一个环节。所以在出现DNS解析错误时,很多人都会感到手足无措&#x…

【Echarts】曲线图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好,我是全栈小5。 这是《前端》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握…

第七次作业

IPSEC VPPN实验配置 目标:在FW5和FW3之间建立一条IPSEC通道,保证10.0.2.0/24网段可以正常访问到192.168.1.0/24 1.FW1和FW2进行双机热备(之前实验没保存,可看上个实验) 还有一些配置前面实验有。 2.场景选择点对点…

探究精酿啤酒的秘密:原料中的天然酵母与纯净水质

在啤酒的世界中,Fendi Club精酿啤酒以其与众不同的口感和深远的余味吸引了全球的啤酒爱好者。而这一切,都归功于其选用的上好原料,特别是天然酵母和纯净水质。 天然酵母是啤酒的灵魂。与工业生产的啤酒酵母不同,天然酵母富含丰富的…

分布式之Ribbon使用以及原理

Ribbon使用以及原理 1、负载均衡的两种方式 服务器端负载均衡 传统的方式前端发送请求会到我们的的nginx上去,nginx作为反向代理,然后路由给后端的服务器,由于负载均衡算法是nginx提供的,而nginx是部署到服务器端的,所…

20240310-1-Java后端开发知识体系

Java 基础 知识体系 Questions 1. HashMap 1.8与1.7的区别 1.71.8底层结构数组链表数组链表/红黑树插入方式头插法尾插法计算hash值4次位运算5次异或运算1次位运算1次异或运算扩容、插入先扩容再插入先插入再扩容扩容后位置计算重新hash原位置或原位置旧容量 (1) 扩容因子…

arcgis中.mpk和.lpk以及.mxd文件

一、概念 图层包 (.lpk) 中包括图层属性和图层所引用的数据集。利用图层包,可保存和共享与图层相关的所有信息,如图层的符号化、标注、表属性和数据等。地图包 (.mpk) 包含地图文档 (.mxd)、所含图层引用的所有数据以及其他地图项目(如图形、…

论文笔记:Evaluating the Performance of Large Language Models on GAOKAO Benchmark

1 论文思路 采用zero-shot prompting的方式,将试题转化为ChatGPT的输入 对于数学题,将公式转化为latex输入 主观题由专业教师打分 2 数据 2010~2022年,一共13年间的全国A卷和全国B卷 3 结论 3.1 不同模型的zeroshot 高考总分 3.2 各科主…

向量化编程书籍推荐

文章目录 1. 书籍清单 1. 书籍清单 《Linear Algebra and Its Applications》 by Gilbert Strang 这本书是线性代数的经典教材,线性代数是向量化编程的基础。它涵盖了向量、矩阵、线性变换等内容,对理解向量化编程的数学概念非常有帮助《NumPy Beginner…