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

Java设计模式之《状态模式》

目录

1、状态模式

1.1、介绍

1.2、设计背景

1.3、适用场景

2、实现

2.1、if-else实现

2.2、状态模式实现

2.3、最终版

1、关于if-else的优化

2、状态模式下的优化

3、ArrayList 配置“状态流”

3、总结


前言

关于Java的设计模式分类如下:

对于状态模式的组件组成,如下所示:


1、状态模式

1.1、介绍

允许一个对象在其内部状态发生改变时,行为也随之改变,看起来就像对象修改了它的类。

  • 状态模式就是把“状态”封装成独立的类,不同状态下执行不同的逻辑
  • 状态切换由对象自己控制,而不是外部用 if-else/switch来判断

1.2、设计背景

问题场景:

if (status == "UNPAID") { /* 处理支付 */ }
else if (status == "PAID") { /* 处理发货 */ }
else if (status == "SHIPPED") { /* 处理收货 */ }
  • 每加一个状态,要修改这段代码
  • 状态切换逻辑和行为混在一起,难维护

状态模式的好处:

  • 每个状态的逻辑单独放在一个类中
  • 遵循 开闭原则(新增状态只加类,不改原来代码)
  • 状态的切换由对象自身控制,不依赖外部复杂判断

两者对比,如下所示:

1.3、适用场景

在项目中常用的场景如下:

  • Spring StateMachine(状态机框架)
  • 订单系统:未支付 → 已支付 → 已发货 → 已完成
  • 工作流引擎(Flowable、Activiti)
  • Netty Channel 状态:UNREGISTERED → REGISTERED → ACTIVE → INACTIVE

💡 因此:

  • 如果状态很少且不会变,可以用 if-else
  • 如果状态多、变化频繁,并且有复杂行为 => 用状态模式

2、实现

2.1、if-else实现

public class Order {public static final int UNPAID = 0;public static final int PAID = 1;public static final int SHIPPED = 2;public static final int DONE = 3;private int status = UNPAID;public void process() {if (status == UNPAID) {System.out.println("当前订单未支付,执行支付逻辑...");status = PAID;} else if (status == PAID) {System.out.println("订单已支付,执行发货逻辑...");status = SHIPPED;} else if (status == SHIPPED) {System.out.println("订单已发货,执行收货逻辑...");status = DONE;} else if (status == DONE) {System.out.println("订单已完成");} else {System.out.println("未知订单状态");}}
}

测试:

public class Test {public static void main(String[] args) {Order order = new Order();order.process(); // 支付order.process(); // 发货order.process(); // 收货order.process(); // 已完成}
}

这种方式短期内可用,但问题比较明显:

1、集中式 if-else

所有状态逻辑都在一个方法里面,方法不断膨胀,维护困难。

2、违反开闭原则

新增状态时必须修改这个方法的代码,容易引入 bug。

3、状态切换逻辑分散

可能在多个方法都有类似的 if-else,改动的时候要到处找。

4、可读性差

状态和行为耦合得很紧,不直观。

2.2、状态模式实现

订单状态流转

1、定义状态接口

public interface OrderState {void handle(OrderContext context);
}

2、具体状态类

public class UnpaidState implements OrderState {public void handle(OrderContext context) {System.out.println("当前订单未支付,执行支付逻辑...");context.setState(new PaidState()); // 切换状态}
}public class PaidState implements OrderState {public void handle(OrderContext context) {System.out.println("订单已支付,执行发货逻辑...");context.setState(new ShippedState());}
}public class ShippedState implements OrderState {public void handle(OrderContext context) {System.out.println("订单已发货,执行收货逻辑...");context.setState(new DoneState());}
}public class DoneState implements OrderState {public void handle(OrderContext context) {System.out.println("订单已完成");}
}

3、环境类

public class OrderContext {private OrderState state;public OrderContext(OrderState state) { this.state = state; }public void setState(OrderState state) { this.state = state; }public void request() { state.handle(this); }
}

测试

public class Test {public static void main(String[] args) {OrderContext order = new OrderContext(new UnpaidState());order.request(); // 支付order.request(); // 发货order.request(); // 收货order.request(); // 已完成}
}输出:
当前订单未支付,执行支付逻辑...
订单已支付,执行发货逻辑...
订单已发货,执行收货逻辑...
订单已完成

基于前面的if-else和状态模式都需要多次去调用方法,因此可以对调用次数进行优化。

2.3、最终版

1、关于if-else的优化

public class Order {private int status = 0;private static final List<Integer> PROCESS_LIST = List.of(0, // UNPAID1, // PAID2, // SHIPPED3  // DONE);public void process() {if (status == 0) {System.out.println("未支付 -> 支付");status = 1;} else if (status == 1) {System.out.println("已支付 -> 发货");status = 2;} else if (status == 2) {System.out.println("已发货 -> 收货");status = 3;} else {System.out.println("订单完成");}}public static void main(String[] args) {Order order = new Order();PROCESS_LIST.forEach(s -> order.process());}
}

这样避免了写 4 行 order.process(),但 逻辑依旧集中在一个方法里,只是调用更“批量”了。

2、状态模式下的优化

状态模式下,我们可以更灵活地用集合来管理状态流转过程,而且不用去写 if-else。

例子:

interface State {void handle(OrderContext ctx);
}class UnpaidState implements State {public void handle(OrderContext ctx) {System.out.println("当前订单未支付 -> 执行支付逻辑...");ctx.setState(new PaidState());}
}class PaidState implements State {public void handle(OrderContext ctx) {System.out.println("订单已支付 -> 执行发货逻辑...");ctx.setState(new ShippedState());}
}class ShippedState implements State {public void handle(OrderContext ctx) {System.out.println("订单已发货 -> 执行收货逻辑...");ctx.setState(new DoneState());}
}class DoneState implements State {public void handle(OrderContext ctx) {System.out.println("订单已完成");}
}class OrderContext {private State state;public OrderContext(State state) {this.state = state;}public void setState(State state) {this.state = state;}public void process() {state.handle(this);}
}

驱动代码:用集合 + 循环执行

public class TestOrder {public static void main(String[] args) {OrderContext order = new OrderContext(new UnpaidState());// 一直循环直到状态是 DoneStatewhile (!(order.state instanceof DoneState)) {order.process();}// 最后一遍处理完成状态order.process();}
}

特点

  • 不用写多行 request(),直接用循环驱动
  • 如果状态机变长/变短,不影响调用逻辑
  • 也可以设计一个 List 状态链 提前加载好,遍历一次性跑完

3、ArrayList 配置“状态流”

状态模式也可以结合 状态数组

List<State> flow = List.of(new UnpaidState(),new PaidState(),new ShippedState(),new DoneState()
);OrderContext ctx = new OrderContext(flow.get(0));
for (State state : flow) {ctx.setState(state);ctx.process();
}
  • 优势:业务状态流程可以从配置文件甚至数据库加载,不用改代码
  • 实现可拥抱灵活性,比如读取“审批流”、“工单流”这些可配置流程


3、总结

如下所示:


总结

        状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为。模式中包含上下文抽象状态具体状态角色。

        优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。缺点是可能增加系统类的数量和复杂性。适用场景如自动售货机的状态转换、线程状态管理等。


参考文章:

1、设计模式第21讲——状态模式(State)-CSDN博客文章浏览阅读6.7k次,点赞22次,收藏104次。状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为。模式中包含上下文、抽象状态和具体状态角色。优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。缺点是可能增加系统类的数量和复杂性。适用场景如自动售货机的状态转换、线程状态管理等。代码示例展示了自动售卖机如何利用状态模式实现不同状态的切换。 https://blog.csdn.net/weixin_45433817/article/details/131521862?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522d157caaef17e4af5a1ebe4b41acb1286%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=d157caaef17e4af5a1ebe4b41acb1286&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-131521862-null-null.142^v102^control&utm_term=%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F&spm=1018.2226.3001.4187

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

相关文章:

  • 从根源解决 VMware 每次重启 Windows 系统后无法进行复制文件等操作的问题
  • 矩阵的秩几何含义
  • openssh 版本回退
  • Spring Ai (Function Calling / Tool Calling) 工具调用
  • 78-dify案例分享-零基础上手 Dify TTS 插件!从开发到部署免费文本转语音,测试 + 打包教程全有
  • 使用【阿里云百炼】搭建自己的大模型
  • Linux网络设备分析
  • 构建绿色园区新方案:能源监测+用电安全的综合能源管理系统
  • LeetCode - 227. 基本计算器 II
  • C++ `std::map` 解析:`find`, `end`, `insert` 和 `operator[]`
  • redis 在 nodejs 中如何应用?
  • 常用 Kubernetes (K8s) 命令指南
  • DevSecOps 集成 CI/CD Pipeline:实用指南
  • 【RAGFlow代码详解-30】构建系统和 CI/CD
  • 【智能化解决方案】大模型智能推荐选型系统方案设计
  • 简明 | ResNet特点、残差模块、残差映射理解摘要
  • VGVLP思路探索和讨论
  • C++ 并发编程中的锁:总结与实践
  • 绝命毒师模拟器2|单机+联机+绝命毒师模拟器1 全DLC(Drug Dealer Simulator 2+1)免安装中文版
  • 事件驱动架构详解
  • AI Agent安全的“阿喀琉斯之踵”:深度解析MCP核心风险与纵深防御架构
  • Python爬虫: 分布式爬虫架构讲解及实现
  • mysql是怎样运行的(梳理)
  • Java基础第二课:hello word
  • 传统联邦 VS 联邦+大模型
  • freeModbus TCP收发数据一段时间后,出现掉线情况(time out问题)
  • 依托边缘计算方案,移动云全面化解算力、效率、安全平衡难题
  • Wireshark捕获数据的四种层次
  • 【Python数据分析】商品数据可视化大屏项目
  • YggJS RButton 按钮组件 v1.0.0 使用教程