设计模式(二十一)行为型:状态模式详解

设计模式(二十一)行为型:状态模式详解

状态模式(State Pattern)是 GoF 23 种设计模式中的行为型模式之一,其核心价值在于允许一个对象在其内部状态改变时改变其行为,使得对象看起来像是修改了它的类。它通过将与特定状态相关的行为封装到独立的状态类中,将庞大的条件分支(如 if-elseswitch-case)转化为对象间的委托关系,从而实现行为的动态切换与高度可扩展性。状态模式是构建复杂状态机、工作流引擎、游戏角色行为、网络连接管理、订单生命周期、UI 状态管理等系统的理想选择,是将“状态驱动行为”这一自然逻辑优雅映射到面向对象设计的关键范式。

一、详细介绍

状态模式解决的是“一个对象的行为取决于其内部状态,且状态数量较多、状态转换复杂、行为随状态频繁变化”的问题。在传统设计中,通常使用条件语句(如 switch)根据当前状态决定执行何种行为。这导致:

  • 代码臃肿:所有状态相关的行为集中在单一类中,方法庞大。
  • 难以维护:新增状态或修改状态转换逻辑需要修改大量 switch 语句。
  • 违反单一职责原则:一个类承担了所有状态的行为。
  • 违反开闭原则:对扩展开放,对修改关闭。

状态模式的核心思想是:将每个状态封装成一个独立的类,每个状态类实现与该状态相关的行为。原对象(上下文)持有当前状态对象的引用,并将状态相关的行为委托给当前状态对象执行

该模式包含以下核心角色:

  • Context(上下文):定义客户端使用的接口,维护一个对 State 对象的引用,表示当前状态。它将状态相关的行为委托给当前状态对象。
  • State(状态接口):定义所有具体状态类共有的接口,声明与状态相关的行为方法(如 handle())。
  • ConcreteStateA, ConcreteStateB, …(具体状态类):实现 State 接口,封装与特定状态相关的行为。每个具体状态类知道在特定操作下应如何响应,并可能在响应后改变上下文的当前状态(即状态转换)。

状态模式的关键优势:

  • 消除复杂条件语句:将 switch 逻辑转化为多态方法调用。
  • 符合开闭原则:新增状态只需添加新的具体状态类,无需修改现有代码。
  • 符合单一职责原则:每个状态类只负责一种状态的行为。
  • 提高可维护性:状态行为集中,逻辑清晰。
  • 支持动态状态转换:状态转换由状态对象内部决定或由上下文协调。

与“策略模式”相比,策略模式关注算法的替换,状态模式关注状态驱动的行为变化;策略通常由客户端选择,状态由内部逻辑自动转换。与“观察者模式”相比,观察者是一对多通知,状态是单对象行为切换。与“命令模式”相比,命令封装请求,状态封装行为

状态模式适用于:

  • 对象有明确的状态概念(如订单:新建、已支付、已发货、已完成)。
  • 行为随状态变化而变化。
  • 状态转换逻辑复杂。
  • 需要避免庞大的条件语句。

二、状态模式的UML表示

以下是状态模式的标准 UML 类图:

has current
implements
implements
implements
Context
-state: State
+request()
+setState(state: State)
+getState()
«interface»
State
+handle(context: Context)
ConcreteStateA
+handle(context: Context)
ConcreteStateB
+handle(context: Context)
ConcreteStateC
+handle(context: Context)

图解说明

  • Context 持有对 State 的引用,代表当前状态。
  • Contextrequest() 方法将调用委托给当前 Statehandle()
  • ConcreteState 实现 handle(),执行特定于该状态的行为,并可能调用 ContextsetState() 来触发状态转换。
  • 状态转换可以由状态对象自身决定,或由 Context 根据业务逻辑协调。

三、一个简单的Java程序实例及其UML图

以下是一个 TCP 连接状态机的简化示例,包含 CLOSED, LISTEN, ESTABLISHED, CLOSE_WAIT 状态。

Java 程序实例
// 状态接口
interface TCPState {void activeOpen(TCPConnection context);void passiveOpen(TCPConnection context);void close(TCPConnection context);void acknowledge(TCPConnection context);void send(TCPConnection context);String getStateName(); // 用于显示
}// 上下文:TCP连接
class TCPConnection {private TCPState currentState;// 预定义状态实例(可单例)private static final TCPState CLOSED = new ClosedState();private static final TCPState LISTEN = new ListenState();private static final TCPState ESTABLISHED = new EstablishedState();private static final TCPState CLOSE_WAIT = new CloseWaitState();public TCPConnection() {this.currentState = CLOSED;System.out.println("🔌 连接初始化为 CLOSED 状态");}// 状态相关操作,委托给当前状态public void activeOpen() {System.out.println("👉 客户端发起主动打开...");currentState.activeOpen(this);}public void passiveOpen() {System.out.println("👉 服务端发起被动打开...");currentState.passiveOpen(this);}public void close() {System.out.println("👉 发起关闭连接...");currentState.close(this);}public void acknowledge() {System.out.println("👉 收到确认...");currentState.acknowledge(this);}public void send() {System.out.println("👉 发送数据...");currentState.send(this);}// 状态转换方法public void changeState(TCPState newState) {if (this.currentState != null) {System.out.println("🔄 状态转换: " + this.currentState.getStateName() + " → " + newState.getStateName());}this.currentState = newState;}// 获取当前状态(用于状态判断,可选)public TCPState getCurrentState() {return currentState;}// 预定义状态的获取方法(简化客户端使用)public static TCPState getClosedState() { return CLOSED; }public static TCPState getListenState() { return LISTEN; }public static TCPState getEstablishedState() { return ESTABLISHED; }public static TCPState getCloseWaitState() { return CLOSE_WAIT; }
}// 具体状态:CLOSED
class ClosedState implements TCPState {@Overridepublic void activeOpen(TCPConnection context) {System.out.println("  ✅ CLOSED: 执行主动打开 -> 发送 SYN, 进入 SYN_SENT (本例简化为直接进入 ESTABLISHED)");context.changeState(TCPConnection.getEstablishedState());}@Overridepublic void passiveOpen(TCPConnection context) {System.out.println("  ✅ CLOSED: 执行被动打开 -> 进入 LISTEN");context.changeState(TCPConnection.getListenState());}@Overridepublic void close(TCPConnection context) {System.out.println("  ⚠️  CLOSED: 连接已关闭,无需操作");}@Overridepublic void acknowledge(TCPConnection context) {System.out.println("  ❌ CLOSED: 无法处理确认");}@Overridepublic void send(TCPConnection context) {System.out.println("  ❌ CLOSED: 连接未建立,无法发送");}@Overridepublic String getStateName() {return "CLOSED";}
}// 具体状态:LISTEN
class ListenState implements TCPState {@Overridepublic void activeOpen(TCPConnection context) {System.out.println("  ✅ LISTEN: 收到 SYN -> 发送 SYN-ACK, 进入 SYN_RECEIVED (本例简化为进入 ESTABLISHED)");context.changeState(TCPConnection.getEstablishedState());}@Overridepublic void passiveOpen(TCPConnection context) {System.out.println("  ⚠️  LISTEN: 已在监听状态");}@Overridepublic void close(TCPConnection context) {System.out.println("  ✅ LISTEN: 关闭监听 -> 进入 CLOSED");context.changeState(TCPConnection.getClosedState());}@Overridepublic void acknowledge(TCPConnection context) {System.out.println("  ❌ LISTEN: 未建立连接,无法确认");}@Overridepublic void send(TCPConnection context) {System.out.println("  ❌ LISTEN: 连接未建立,无法发送");}@Overridepublic String getStateName() {return "LISTEN";}
}// 具体状态:ESTABLISHED
class EstablishedState implements TCPState {@Overridepublic void activeOpen(TCPConnection context) {System.out.println("  ⚠️  ESTABLISHED: 连接已建立,无需打开");}@Overridepublic void passiveOpen(TCPConnection context) {System.out.println("  ⚠️  ESTABLISHED: 连接已建立,无需打开");}@Overridepublic void close(TCPConnection context) {System.out.println("  ✅ ESTABLISHED: 发送 FIN -> 进入 FIN_WAIT_1 (本例简化为进入 CLOSE_WAIT)");context.changeState(TCPConnection.getCloseWaitState());}@Overridepublic void acknowledge(TCPConnection context) {System.out.println("  ✅ ESTABLISHED: 确认数据包");// 通常发送 ACK}@Overridepublic void send(TCPConnection context) {System.out.println("  ✅ ESTABLISHED: 数据发送成功");// 发送数据包}@Overridepublic String getStateName() {return "ESTABLISHED";}
}// 具体状态:CLOSE_WAIT
class CloseWaitState implements TCPState {@Overridepublic void activeOpen(TCPConnection context) {System.out.println("  ❌ CLOSE_WAIT: 连接正在关闭,无法打开");}@Overridepublic void passiveOpen(TCPConnection context) {System.out.println("  ❌ CLOSE_WAIT: 连接正在关闭,无法打开");}@Overridepublic void close(TCPConnection context) {System.out.println("  ✅ CLOSE_WAIT: 发送 FIN -> 进入 LAST_ACK (本例简化为进入 CLOSED)");context.changeState(TCPConnection.getClosedState());}@Overridepublic void acknowledge(TCPConnection context) {System.out.println("  ✅ CLOSE_WAIT: 确认对方的 FIN");}@Overridepublic void send(TCPConnection context) {System.out.println("  ⚠️  CLOSE_WAIT: 可能允许发送最后数据,但本例禁止");}@Overridepublic String getStateName() {return "CLOSE_WAIT";}
}// 客户端使用示例
public class StatePatternDemo {public static void main(String[] args) {System.out.println("🌐 TCP 连接状态机 - 状态模式示例\n");TCPConnection connection = new TCPConnection();System.out.println("\n--- 客户端连接流程 ---");connection.activeOpen(); // CLOSED -> ESTABLISHEDconnection.send();       // 发送数据connection.acknowledge(); // 确认connection.close();      // ESTABLISHED -> CLOSE_WAIT -> CLOSEDSystem.out.println("\n--- 服务端连接流程 ---");connection.passiveOpen(); // CLOSED -> LISTENconnection.activeOpen();  // LISTEN -> ESTABLISHED (收到客户端 SYN)connection.send();        // 发送数据connection.close();       // ESTABLISHED -> CLOSE_WAIT -> CLOSEDSystem.out.println("\n--- 在 CLOSED 状态尝试无效操作 ---");connection.send();        // 应提示无法发送}
}
实例对应的UML图(简化版)
has current
implements
implements
implements
implements
TCPConnection
-currentState: TCPState
+activeOpen()
+passiveOpen()
+close()
+acknowledge()
+send()
+changeState(newState: TCPState)
«interface»
TCPState
+activeOpen(context: TCPConnection)
+passiveOpen(context: TCPConnection)
+close(context: TCPConnection)
+acknowledge(context: TCPConnection)
+send(context: TCPConnection)
+getStateName()
ClosedState
+activeOpen(context: TCPConnection)
+passiveOpen(context: TCPConnection)
+close(context: TCPConnection)
+acknowledge(context: TCPConnection)
+send(context: TCPConnection)
+getStateName()
ListenState
+activeOpen(context: TCPConnection)
+passiveOpen(context: TCPConnection)
+close(context: TCPConnection)
+acknowledge(context: TCPConnection)
+send(context: TCPConnection)
+getStateName()
EstablishedState
+activeOpen(context: TCPConnection)
+passiveOpen(context: TCPConnection)
+close(context: TCPConnection)
+acknowledge(context: TCPConnection)
+send(context: TCPConnection)
+getStateName()
CloseWaitState
+activeOpen(context: TCPConnection)
+passiveOpen(context: TCPConnection)
+close(context: TCPConnection)
+acknowledge(context: TCPConnection)
+send(context: TCPConnection)
+getStateName()

运行说明

  • TCPConnection 是上下文,持有当前 TCPState
  • 每个操作(activeOpen, close 等)被委托给当前状态对象的对应方法。
  • 状态方法执行特定行为,并可能调用 changeState() 触发状态转换。
  • 不同状态对同一操作的响应不同(如 CLOSEDESTABLISHEDsend 的处理)。
  • 状态转换逻辑内置于状态类中,清晰且可扩展。

四、总结

特性说明
核心目的允许对象在状态改变时改变行为,消除条件分支
实现机制将状态行为封装到独立类,上下文委托调用
优点消除复杂条件语句、符合开闭/单一职责原则、提高可维护性、支持动态转换
缺点增加类数量、状态转换逻辑可能分散、简单状态机可能过度设计
适用场景复杂状态机、工作流、订单生命周期、游戏AI、UI状态管理
不适用场景状态极少、行为简单、状态转换固定

状态模式使用建议

  • 状态类可设计为单例(无状态或共享状态)。
  • 状态转换可由状态对象自身决定,或由上下文根据业务规则协调。
  • 可结合“工厂模式”创建状态对象。
  • 在 Java 中,enum 可实现简单状态模式(每个枚举常量实现接口)。

架构师洞见:
状态模式是“有限状态机(FSM)”在面向对象中的优雅实现。在现代架构中,其思想已演变为工作流引擎(如 Camunda, Airflow)事件驱动状态管理(Redux, Vuex)服务编排(Kubernetes Operators)AI Agent 的决策状态 的核心。例如,Redux 的 reducer 函数根据 action 和当前 state 计算新 state,本质是状态模式的函数式变体;微服务的 Saga 模式管理分布式事务状态;在自动驾驶中,车辆行为模式(巡航、变道、停车)是复杂的状态机。

未来趋势是:状态模式将与形式化方法结合,实现状态机的自动验证;在量子计算中,量子态的演化可建模为状态转换;在元宇宙中,虚拟角色的行为状态(行走、战斗、交互)由状态模式驱动;在AI中,LLM Agent 的“思考-行动-观察”循环可视为一个高级状态机。

掌握状态模式,是设计复杂业务逻辑、高可靠性系统的关键。作为架构师,应在面对“多状态、多行为、复杂转换”的领域模型时,果断采用状态模式。它不仅是模式,更是系统确定性的保障——它将混沌的条件逻辑转化为清晰、可验证、可演进的状态图,让系统的每一次行为变迁都变得可预测、可追溯、可管理,从而构建出真正健壮、可信赖的软件系统。

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

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

相关文章

深入理解 Doris Compaction:提升查询性能的幕后功臣

在 Doris 的数据存储与查询体系里,Compaction 是保障查询效率、优化存储结构的关键机制。如果你好奇 Doris 如何在高频写入后仍能高效响应查询,或是想解决数据版本膨胀带来的性能问题,这篇关于 Compaction 的深度解析值得收藏 👇 …

css 实现虚线效果的多种方式

使用边框实现虚线 通过设置元素的边框样式来实现虚线效果。以下为示例代码: .dashed {border: 1px dashed black; }使用 CSS 伪元素实现虚线 使用伪元素来模拟虚线的效果。以下为示例代码: .dashed::before {content: "";display: block;height: 1px;border-bo…

深入剖析 RocketMQ 分布式事务:原理、流程与实践

Apache RocketMQ 是一种分布式消息队列系统,支持分布式事务消息,以确保在分布式系统中数据的一致性。它通过一种基于两阶段提交(2PC)的机制结合补偿逻辑来实现分布式事务的最终一致性。以下是对 RocketMQ 分布式事务的详细讲解,包括其核心概念…

具身智能 自动驾驶相关岗位的技术栈与能力地图

一、硬技能技术栈(优先级排序) 1. 核心领域技术(★★★★★)技术方向具体技能学习建议大模型实战- VLA架构(RT-2、PaLM-E)开发/微调- 多模态对齐(CLIP、Flamingo)- 生成式策略&#…

实现了加载 正向 碰撞 雅可比 仿真

""" # 此示例从 URDF 文件中加载一个 UR10 机械臂的模型 # 随后演示 Pinocchio 库的基本功能,如正向运动学计算 # 雅可比矩阵计算、碰撞检测以及动力学仿真 """ # 导入 meshcat 的几何模块,用于创建和管理可视化的几何对象 import meshcat.geo…

【0基础PS】PS工具详解--画笔工具

目录前言一、画笔工具的位置与快捷键​二、画笔工具选项栏设置​三、画笔工具的进阶应用​四、常见问题及解决方法​总结前言 在 Photoshop 的众多工具中,画笔工具无疑是极具创造力和实用性的工具之一。无论是进行图像绘制、照片修饰,还是特效制作&…

window10和ubuntu22.04双系统之卸载ubuntu系统

window10和ubuntu22.04双系统之卸载ubuntu系统)1. 删除Ubuntu系统占用的磁盘分区(在Windows下操作)2. 删除ubuntu开机引导项1. winr出来终端提示框后输入2. 然后会在命令行中显示电脑的硬盘列表,输入命令选择安装Windows的那个硬盘…

(C++)C++类和类的方法(基础教程)(与Python类的区别)

前言&#xff1a; 本篇博客建议搭配&#xff1a;&#xff08;Python&#xff09;类和类的方法&#xff08;基础教程介绍&#xff09;&#xff08;Python基础教程&#xff09;-CSDN博客 一起学习使用&#xff1b; 源代码&#xff1a; #include <iostream> #include &…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博文章数据可视化分析-文章分类下拉框实现

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解微博文章数据可视化分析-文章分类下拉框实现…

Git命令保姆级教程

Git 入门网站 https://learngitbranching.js.org/?localezh_CN Git 命令 git init // 在本地目录内部会生成.git文件夹 git initgit clone // 从git服务器拉取代码 // 代码下载完成后在当前文件夹中会有一个 shop 的目录&#xff0c;通过 cd shop 命令进入目录。 git clone ht…

Java Ai For循环 (day07)

循环结构 for&#xff1a;循环语句的作用&#xff1a;可以将一段代码重复的执行很多次for 循环语句格式&#xff1a;执行流程&#xff1a; 初始化语句执行条件判断语句&#xff0c;看结果是 true&#xff0c;还是 false false结束&#xff0c;true继续执行循环体语句执行条件控…

Directory Opus 使用优化

自定义快捷键 Directory Opus 移动标签到另一栏 设置快捷键&#xff1a;ctrl←/→ 设置步骤&#xff1a; 打开【设置】—>选择【自定义工具栏和快捷键】 选择【新建】—>【新建窗口快捷键】 输入快捷键命令 Go TABMOVEother此时可以点击运行进行测试&#xff0c;…

Qt知识点2『Ubuntu24.04.2安装Qt5.12.9各种报错』

问题1&#xff1a;Qt安装完毕后&#xff0c;新建一个最简单的测试程序&#xff0c;但是QtCreator左侧构建的三个按钮呈现灰色&#xff0c;无法进行构建操作答&#xff1a;进入QtCreator的Kits界面&#xff08;工具-选项&#xff09;&#xff0c;点击"自动检测"下的De…

TS面试题

1.TS有哪些类型&#xff08;对比与js&#xff09;&#xff1f;关键字/语法用途示例any关闭类型检查let a: any 4unknown类型安全的 anylet u: unknown 4; if (typeof u number) …never永不存在的值function err(): never { throw 0; }void无返回值function f(): void {}enu…

借助Early Hints和HarperDB改善网页性能

对电商网站来说&#xff0c;糟糕的页面性能可能会增加交易放弃率。一直以来&#xff0c;人们会使用CDN进行缓存从而缩短页面加载时间&#xff0c;但即便实施了强大的缓存&#xff0c;消费者在通过移动网络访问这些网站时可能仍然会需要频繁等待。最近诞生了一种名为“早期提示”…

MEMS陀螺如何成为无人机稳定飞行的核心?

在无人机自主翱翔、灵活机动并适应多变环境的背后&#xff0c;对其运动状态——尤其是姿态——的精确感知是基石。作为飞行控制系统&#xff08;飞控&#xff09;的“内耳”&#xff0c;陀螺仪实时捕捉机体绕X、Y、Z三轴的旋转角速度。这一核心数据是飞控进行姿态解算和维持飞行…

腾讯云拉取docker镜像失败怎么办

ps:我直接按照步骤1和2就解决了 以下内容来自豆包 在腾讯云服务器上拉取 Docker 镜像失败&#xff0c;可以按照以下步骤排查和解决&#xff1a; 一、检查网络连接 确认服务器网络正常 bash ping www.baidu.com # 测试公网连通性如果无法 ping 通&#xff0c;检查服务器防火墙…

Apache FOP实践——pdf模板引擎

文章目录 基本概念设计思想具体实践完整应用 基本概念 Apache FOP&#xff08;Formatting Objects Processor&#xff09;是一个基于Java的开源工具&#xff0c;用于将 XSL-FO&#xff08;XSL Formatting Objects&#xff09; 文档转换为PDF、图像等格式。 设计思想 将内容&…

WebRTC核心组件技术解析:架构、作用与协同机制

引言&#xff1a;WebRTC的技术定位与价值 WebRTC&#xff08;Web Real-Time Communication&#xff09;作为一项开源实时通信标准&#xff0c;已成为浏览器原生音视频交互、P2P数据传输的技术基石。自2011年开源以来&#xff0c;其标准化进程由W3C&#xff08;API层&#xff0…

OmniParser:提升工作效率的视觉界面解析工具

OmniParser&#xff1a;基于视觉的用户界面解析工具在现代软件开发中&#xff0c;用户界面的自动化处理变得愈发重要。OmniParser 是一个强大的工具&#xff0c;旨在将用户界面的截图解析为结构化的、易于理解的元素&#xff0c;从而显著提升了大型语言模型&#xff08;如GPT-4…