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

行为设计模式之State(状态)设计模式

行为设计模式之State(状态)设计模式

摘要:
本文介绍了行为设计模式中的State(状态)模式。该模式允许对象在内部状态改变时改变行为,解决对象行为依赖于状态的多分支条件判断问题。文章展示了状态模式的结构、适用场景以及一个售货机状态转换的代码示例。典型应用场景包括对象行为随状态显著变化、需避免大量条件分支、状态转换规则明确且可能变化、状态数量较多或可能增加等情况。常见应用领域涵盖游戏开发、用户界面、工作流引擎、网络协议和嵌入式系统等。状态模式通过将状态和行为封装到独立类中,提高了代码的可读性、可维护性和扩展性,符合开闭原则。

1)意图

允许一个对象在内部状态改变时改变它的行为。对象看起来似乎改变它的类。

2)结构

在这里插入图片描述

3)适用性

State 模式适用于:

  • 一个对象的行为决定它的状态,并且它必须运行时刻根据改变它的行为。
  • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。
/*** @author psd 行为设计模式之状态设计模式*/
public class StatePattern {public static void main(String[] args) {Context context = new Context();System.out.println("状态是:" + context.getState() + " 数量" + context.getResidueCount());// 购买成功 count = 2context.request();// 购买成功 count = 1context.request();// 购买成功 count = 0context.request();System.out.println("状态是:" + context.getState() + " 数量" + context.getResidueCount());// 无货,等待补货 count = 5context.request();System.out.println("状态是:" + context.getState() + " 数量" + context.getResidueCount());context.request();System.out.println("状态是:" + context.getState() + " 数量" + context.getResidueCount());}
}/*** 售卖机*/
class Context{private int residueCount;private State state;public int getResidueCount() {return residueCount;}public void setResidueCount(int residueCount) {this.residueCount = residueCount;}public State getState() {return state;}public void setState(State state) {this.state = state;}public void request(){state.handler(this);}public Context() {this.state = new StateA();this.residueCount = 3;}
}interface State{void handler(Context context);
}/*** 售货机状态A 有货*/
class StateA implements State{@Overridepublic void handler(Context context) {int residueCount = context.getResidueCount();if (residueCount >= 1){System.out.println("商品购买成功........");context.setResidueCount(residueCount - 1);if (0 == context.getResidueCount()){context.setState(new StateB());}}else {System.out.println("购买失败......");}}
}class StateB implements State{@Overridepublic void handler(Context context) {int residueCount = context.getResidueCount();if (0 == residueCount){System.out.println("商品购买失败....商品待补货");context.setResidueCount(5);System.out.println("补货成功,请重新购买");context.setState(new StateA());}}
}

4)以下是状态设计模式的典型使用场景:

1、对象拥有多个状态,且行为随状态显著变化:

这是最核心的场景。当一个对象的行为(方法执行的操作)会因其当前所处的状态(内部数据值)不同而发生根本性改变时。

例子:

电梯系统: 电梯有开门、关门、运行中、停止、故障等状态。按下楼层按钮这个行为,在开门状态下可能无效或需要等待关门,在运行中状态下会将目标楼层加入队列,在停止状态下会启动运行。

网络连接: 连接有已连接、正在连接、已断开、超时等状态。发送数据在已连接状态下会发送,在已断开状态下会尝试重连或报错,在正在连接状态下会排队或拒绝。

订单系统: 订单有待支付、已支付、已发货、已收货、已完成、已取消、退款中等状态。取消订单在待支付状态下可以取消,在已发货状态下可能需要联系客服拦截,在已完成状态下则无法取消。

2、需要避免大量条件分支语句(if-else / switch-case):

当根据对象状态来决定行为的逻辑变得非常复杂,导致一个方法(如handleRequest())内部充斥着大量的条件判断语句时。这不仅代码臃肿、难以阅读和维护,而且增加新状态或修改状态转换逻辑非常容易出错。

状态模式的价值: 它将每个状态的行为封装到独立的状态类中。主对象(Context)只需持有当前状态对象的引用,并将请求委托给当前状态对象处理。这样,添加新状态只需添加新的状态类,修改状态行为只需修改对应的状态类,极大地简化了Context类的逻辑,符合开闭原则。

3、状态转换规则相对明确且可能发生变化:

状态之间的转换有明确的逻辑(例如,订单从待支付只能转换到已支付或已取消)。状态模式将状态转换逻辑也封装在状态类内部(或一个集中的地方),使得转换规则更清晰、更易于管理和修改。

如果业务规则变化导致状态转换逻辑需要调整,修改集中在相关的状态类中,而不是散落在庞大的条件语句里。

4、状态数量较多或可能增加:

当状态数量较多(比如超过 3-5 个)时,使用状态模式的优势会愈发明显。它将复杂的状态相关行为分散到多个较小的类中,提高了代码的可读性和可维护性。

当预期未来状态可能会增加时,状态模式提供了良好的扩展性。添加新状态只需要实现新的状态类,并在适当的转换点引入它,通常不需要修改现有的状态类(除非转换规则变化)或Context类的主要逻辑。

5、需要清晰地表示状态及其行为:

状态模式显式地将每个状态及其对应的行为定义为一个独立的类。这使得状态的概念在代码中变得非常清晰和具体,有助于开发者理解整个状态机的工作流程。文档性也更好。

常见应用领域举例:

游戏开发:

游戏角色状态(站立、行走、奔跑、跳跃、攻击、受伤、死亡)。每种状态下角色的动画、移动速度、碰撞检测、输入响应都不同。

NPC AI 状态(巡逻、追击、攻击、逃跑、闲置)。

游戏流程状态(主菜单、游戏中、暂停、游戏结束、加载中)。

用户界面 (UI) / 前端开发:

按钮状态(正常、悬停、按下、禁用),每种状态有不同的外观和点击响应。

复杂组件状态(如一个文件上传组件:等待选择文件、上传中、上传成功、上传失败、暂停)。

表单验证状态(初始、验证中、有效、无效)。

工作流引擎:

业务流程(如订单处理、请假审批、报销流程)涉及多个状态节点,每个节点有特定的操作和允许的流转方向。

网络协议实现:

TCP 连接管理(LISTEN, SYN_SENT, SYN_RECEIVED, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT, CLOSED)。协议栈的行为在每个状态下都严格定义。

嵌入式系统/硬件控制:

设备状态机(如打印机:空闲、预热中、打印中、卡纸、缺墨、关机)。不同状态下对按钮操作或传感器信号的反应不同。

编译器/解释器:

词法分析器(扫描器)在解析不同词法单元(标识符、数字、字符串、运算符)时处于不同的状态。

喜欢我的文章记得点个在看,或者点赞,持续更新中ing…

http://www.dtcms.com/a/250919.html

相关文章:

  • ceil方法
  • WebStorm编辑器侧边栏
  • 40套精品大气黑金系列行业PPT模版分享
  • 【Bluedroid】蓝牙启动之核心模块(startProfiles )初始化与功能源码解析
  • gradle的 build时kaptDebugKotlin 处理数据库模块
  • Laravel 12 更新与之前版本结构变更清单
  • 4.查看、删除数据库
  • 第9章:Neo4j集群与高可用性
  • 基于docker的nocobase本地部署流程
  • 快速使用 Flutter 中的 SnackBar 和 Toast
  • SpringBoot学习day3-SpringBoot注解开发(新闻项目后段基础)
  • 【项目实训】【项目博客#07】HarmonySmartCodingSystem系统前端开发技术详解(5.12-6.15)
  • 工厂模式Factory Pattern
  • KeyOpt
  • 征程 6 Cache 使用场景
  • DNS递归查询
  • 个人AI助理智能体之tool_calling_agent实战指南
  • C# 事件详解
  • 【数据可视化】Pyecharts-家乡地图
  • CppCon 2016 学习: std::accumulate EXPLORING AN ALGORITHMIC EMPIRE
  • 【慧游鲁博】【15】后台管理系统功能完善:仪表盘、多模态交互日志、简单问答词条管理
  • 使用VSCode开发FastAPI指南(二)
  • MCP数据可视化服务器配置依赖
  • origin绘制双Y轴柱状图、双Y轴柱状点线图和双Y轴点线图
  • MCP案例 - 数据可视化客户端
  • Java中的CAS与ABA
  • LLMs之Memory:《LLMs Do Not Have Human-Like Working Memory》翻译与解读
  • Github搜索案例
  • 技术选型指南:如何选择更适合项目的开源语言及其生态系统
  • gpfs的安装配置与部署