当前位置: 首页 > news >正文

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

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

状态模式(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.lryc.cn/news/602673.html

相关文章:

  • python生成 requirement.txt 文件
  • fchown/fchownat系统调用及示例
  • 技术总结|如何使用提升 strlen 的性能?
  • lesson26-2:使用Tkinter打造简易画图软件优化版
  • 数据链路层 和 ARP协议
  • MQTT的原理
  • 华为Huawei 6730交换机查看接口收发光命令 transceiver
  • 9.c语言常用算法
  • Anaconda创建环境报错:CondaHTTPEFTOT: HTTP 403 FORBIDDEN for url
  • Linux中配置haproxy
  • gitlab 在线合并分支a-分支b,解决冲突后,反向合并分支b-分支a
  • 数据结构——图(二、图的存储和基本操作)
  • 人机交互打字游戏
  • Leetcode——11. 盛最多水的容器
  • 力扣-39.组合总和
  • PhpStorm + PHP8.1 + XDebug3 实现断点调试(亲测可用)
  • 面试问题收集——卷积神经网络
  • 从 “看天吃饭” 到 “精准可控”:边缘计算网关如何引爆智慧农业种植变革?
  • 计算机毕设分享-基于SpringBoot的健身房管理系统(开题报告+前后端源码+Lun文+开发文档+数据库设计文档)
  • 服务器多线主要是指什么?
  • 服务器查日志太慢,试试grep组合拳
  • 数据中心入门学习(四):服务器概述与PCIe总线
  • 数据结构面经
  • 坚鹏:AI智能体培训是知行学成为AI智能体创新应用引领者的基础
  • 【Spring Boot 快速开发】一、入门
  • AI技术落地的综合实战经验报告,结合最新行业案例、代码示例及可视化图表,系统阐述AI在开发提效、算法优化与行业应用中的实践路径。
  • Python将Word转换为Excel
  • EXCEL 怎么把汉字转换成拼音首字母
  • 根据发热量确定选择TEC制冷片测评分析学习
  • Open CV图像基本操作可莉版