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

Java行为型模式---状态模式

状态模式基础概念

状态模式(State Pattern)是一种行为型设计模式,其核心思想是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。状态模式将状态相关的行为封装在独立的状态类中,并将状态转换逻辑集中管理,从而使对象的行为可以根据状态动态变化,而不必使用大量的条件语句。

状态模式的核心组件

  1. 状态接口(State) - 定义特定状态下的行为接口,所有具体状态类需实现该接口。
  2. 具体状态类(ConcreteState) - 实现状态接口,封装与特定状态相关的行为。
  3. 上下文(Context) - 持有一个状态对象的引用,负责状态的切换和委托行为到当前状态。

状态模式的实现

下面通过一个简单的自动贩卖机示例展示状态模式的实现:

// 1. 状态接口
interface State {void insertCoin();  // 投币void ejectCoin();   // 退币void selectItem();  // 选择商品void dispense();    // 发放商品
}// 2. 具体状态类 - 没有硬币
class NoCoinState implements State {private VendingMachine machine;  // 持有上下文引用public NoCoinState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("您投入了硬币");machine.setState(machine.getHasCoinState());  // 状态转换}@Overridepublic void ejectCoin() {System.out.println("您还没有投币");}@Overridepublic void selectItem() {System.out.println("请先投币");}@Overridepublic void dispense() {System.out.println("请先投币并选择商品");}
}// 3. 具体状态类 - 有硬币
class HasCoinState implements State {private VendingMachine machine;public HasCoinState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("您已经投过硬币了,无需再投");}@Overridepublic void ejectCoin() {System.out.println("硬币已退回");machine.setState(machine.getNoCoinState());  // 状态转换}@Overridepublic void selectItem() {System.out.println("您选择了商品");machine.setState(machine.getSoldState());  // 状态转换}@Overridepublic void dispense() {System.out.println("请先选择商品");}
}// 4. 具体状态类 - 已售出
class SoldState implements State {private VendingMachine machine;public SoldState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("请稍等,正在出货");}@Overridepublic void ejectCoin() {System.out.println("抱歉,您已经选择了商品,无法退币");}@Overridepublic void selectItem() {System.out.println("请稍等,正在出货");}@Overridepublic void dispense() {if (machine.getCount() > 0) {machine.releaseItem();System.out.println("商品已发放");if (machine.getCount() > 0) {machine.setState(machine.getNoCoinState());  // 还有库存,回到无硬币状态} else {System.out.println("商品已售罄");machine.setState(machine.getSoldOutState());  // 库存不足,转为售罄状态}} else {System.out.println("商品已售罄");machine.setState(machine.getSoldOutState());}}
}// 5. 具体状态类 - 售罄
class SoldOutState implements State {private VendingMachine machine;public SoldOutState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("抱歉,商品已售罄");}@Overridepublic void ejectCoin() {System.out.println("您还没有投币");}@Overridepublic void selectItem() {System.out.println("抱歉,商品已售罄");}@Overridepublic void dispense() {System.out.println("抱歉,商品已售罄");}
}// 6. 上下文 - 自动贩卖机
class VendingMachine {private State noCoinState;private State hasCoinState;private State soldState;private State soldOutState;private State state;  // 当前状态private int count;    // 商品数量public VendingMachine(int count) {this.count = count;// 初始化状态noCoinState = new NoCoinState(this);hasCoinState = new HasCoinState(this);soldState = new SoldState(this);soldOutState = new SoldOutState(this);// 设置初始状态if (count > 0) {state = noCoinState;} else {state = soldOutState;}}// 状态转换方法public void setState(State state) {this.state = state;}// 委托行为到当前状态public void insertCoin() {state.insertCoin();}public void ejectCoin() {state.ejectCoin();}public void selectItem() {state.selectItem();}public void dispense() {state.dispense();}// 其他方法public void releaseItem() {if (count > 0) {count--;}}public int getCount() {return count;}// 获取各种状态(供状态类使用)public State getNoCoinState() {return noCoinState;}public State getHasCoinState() {return hasCoinState;}public State getSoldState() {return soldState;}public State getSoldOutState() {return soldOutState;}
}// 7. 客户端代码
public class StatePatternClient {public static void main(String[] args) {// 创建有2个商品的贩卖机VendingMachine machine = new VendingMachine(2);// 测试流程1:投币 -> 选择商品 -> 出货System.out.println("=== 测试流程1 ===");machine.insertCoin();machine.selectItem();machine.dispense();// 测试流程2:投币 -> 退币System.out.println("\n=== 测试流程2 ===");machine.insertCoin();machine.ejectCoin();// 测试流程3:连续购买2个商品,使贩卖机售罄System.out.println("\n=== 测试流程3 ===");machine.insertCoin();machine.selectItem();machine.dispense();machine.insertCoin();machine.selectItem();machine.dispense();// 尝试在售罄状态下操作System.out.println("\n=== 测试售罄状态 ===");machine.insertCoin();machine.selectItem();}
}

状态模式的应用场景

  1. 工作流系统 - 如订单状态(待支付、已支付、已发货、已完成)
  2. 游戏开发 - 角色状态(站立、行走、跑步、跳跃、攻击)
  3. 状态机实现 - 如协议解析、编译原理中的词法分析器
  4. GUI 组件 - 如按钮状态(正常、悬停、点击、禁用)
  5. 线程状态管理 - 线程的不同状态(新建、就绪、运行、阻塞、终止)
  6. 文档编辑系统 - 文档状态(草稿、审核中、已发布、已归档)

状态模式的优缺点

优点

  • 封装状态行为 - 将特定状态的行为封装在独立的类中,提高代码内聚性
  • 简化条件语句 - 避免使用大量的 if-else 或 switch 语句,使代码更清晰
  • 符合开闭原则 - 可以轻松添加新的状态类,无需修改现有代码
  • 状态转换集中管理 - 状态转换逻辑集中在上下文或状态类中,便于维护
  • 状态变化透明 - 状态变化对客户端透明,客户端无需关心状态转换细节

缺点

  • 类数量增加 - 每个状态都需要一个类,可能导致类爆炸
  • 状态间依赖 - 状态类之间可能存在依赖关系,增加系统复杂度
  • 初始化复杂 - 上下文需要初始化所有可能的状态,增加初始化复杂度
  • 不适用于简单状态 - 对于状态较少或状态转换简单的场景,使用状态模式可能过于繁琐

使用状态模式的注意事项

  1. 合理设计状态接口 - 确保状态接口包含所有可能的行为,避免状态类中出现空实现
  2. 控制状态数量 - 避免定义过多的状态,状态过多会增加系统复杂度
  3. 状态转换逻辑 - 决定状态转换逻辑放在上下文还是状态类中:
    • 上下文控制:集中管理状态转换,状态类更简单
    • 状态类控制:状态类可以自主决定何时转换,更灵活
  4. 状态对象的生命周期 - 决定状态对象是单例还是每次创建新实例
  5. 与策略模式的区别 - 状态模式的状态之间通常有关联和转换,而策略模式的策略之间相互独立
  6. 调试和监控 - 状态模式可能使调试变得复杂,建议添加状态日志或监控机制

总结

状态模式通过将对象的状态相关行为封装在独立的状态类中,并将状态转换逻辑集中管理,实现了对象行为的动态变化。它在不修改对象类的前提下,允许对象在内部状态改变时改变其行为,是处理复杂状态转换场景的理想选择。在实际开发中,状态模式常用于工作流系统、游戏开发、状态机实现等领域。合理使用状态模式可以提高系统的可维护性和可扩展性,但需要注意控制类的数量和状态转换逻辑的复杂度。

http://www.xdnf.cn/news/1149481.html

相关文章:

  • 6-大语言模型—预训练:数据处理
  • SpringBoot项目部署至云服务器
  • simulink系列之汽车应用层信号处理
  • Django母婴商城项目实践(九)- 商品列表页模块
  • LVS的简介以及架构
  • Entity Component System架构
  • 【项目分享】动手做一个TypeC转TTL模块(附带原理图)
  • 加法速算之尾数法
  • Windows11下编译好的opencv4.8-mingw,可下载后直接用
  • java: DDD using sql server 2019 or Oracle21c
  • Linux 密码生成利器:pwgen 命令详解
  • 测试计划(抽奖系统)
  • 考研复习-数据结构-第七章-查找
  • Linux“一切皆文件“设计哲学 与 Linux文件抽象层:struct file与file_operations的架构解析
  • 我做的基础服务项目,是如何实现 API 安全与限流的(短信、邮件、文件上传、钉钉通知)
  • Jenkins 实现项目的构建和发布
  • 企业运维实战:Jenkins 依赖 JDK21 与应用需 JDK1.8 共存方案(含流水线配置)
  • 【ExtendScript Toolkit CC】【PR插件开发】获取当前序列的所有剪辑片段名
  • Java 性能调优实战:JVM 参数配置与 GC 日志分析
  • 深度学习-线性神经网络
  • QCC系列显示交互层的自研技术突破与实践
  • 本地大模型部署工具全解析:LM Studio vs. Ollama 及最佳实践指南
  • 81、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:压栈内容
  • Mybatis学习之简介(一)
  • Django接口自动化平台实现(三)
  • 多式联运物流管理系统的设计与实现(原创)
  • picoCTF 2024: [[NoSQL]] Injection - Writeup
  • 【MATLAB例程】Taylor算法用于TOA(到达时间)的三维标签位置解算,可自适应基站数量。附下载链接
  • 一个基于阿里云的C端Java服务的整体项目架构
  • 后缀树:字符串处理的利器