news 2026/3/10 2:09:05

Java 状态机详解 - 三种状态机实现方式优雅消灭 if-else 嵌套

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 状态机详解 - 三种状态机实现方式优雅消灭 if-else 嵌套

Java 状态机详解:三种实现方式优雅消灭 if-else 嵌套

在 Java 开发中,状态机(Finite State Machine,FSM)是一种经典的设计模式,用于管理对象的有限状态和状态之间的转换。它特别适合处理复杂业务逻辑,比如订单流程(待支付 → 已支付 → 发货 → 收货)、用户认证(未登录 → 登录中 → 已登录)、游戏角色状态(idle → running → jumping)等。

为什么需要状态机?
传统的 if-else 嵌套容易导致代码膨胀、难以维护(“意大利面代码”),尤其当状态和事件增多时。状态机通过将状态和转换逻辑解耦,能让代码更清晰、可扩展、可测试。

下面,我们先看一个 if-else 嵌套的“坏”例子(订单状态机),然后介绍三种优雅实现方式。每种方式都附带完整代码示例(基于 Java 8+,可直接复制运行)。这些方式都能“消灭” if-else 嵌套,但侧重点不同。

问题示例:if-else 嵌套的“坏”代码

假设一个订单系统,有状态:PENDING(待支付)、PAID(已支付)、SHIPPED(已发货)、DELIVERED(已收货)。事件:支付、发货、确认收货。

publicclassOrder{privateStringstate="PENDING";// 初始状态publicvoidpay(){if("PENDING".equals(state)){state="PAID";System.out.println("支付成功,状态变为 PAID");}elseif("PAID".equals(state)){System.out.println("已支付,无需重复");}else{System.out.println("无效操作");}}publicvoidship(){if("PAID".equals(state)){state="SHIPPED";System.out.println("发货成功,状态变为 SHIPPED");}elseif("PENDING".equals(state)){System.out.println("请先支付");}else{System.out.println("无效操作");}}publicvoiddeliver(){if("SHIPPED".equals(state)){state="DELIVERED";System.out.println("收货成功,状态变为 DELIVERED");}else{System.out.println("无效操作");}}publicstaticvoidmain(String[]args){Orderorder=newOrder();order.pay();// 支付成功order.ship();// 发货成功order.deliver();// 收货成功}}

问题:每个方法都有一堆 if-else;新增状态/事件时,所有方法都要改;容易出错、难以扩展。

方式一:枚举 + switch-case(最简单、轻量级)

使用枚举定义状态和事件,在一个方法中用 switch 处理所有转换。适合状态不多(<10个)的简单场景。

优点:代码集中、易理解、无需额外类。
缺点:switch 块可能变长;不适合复杂动作(每个 case 只适合简单逻辑)。
适用:小项目、快速原型。

publicclassOrderEnum{enumState{PENDING,PAID,SHIPPED,DELIVERED}enumEvent{PAY,SHIP,DELIVER}privateStatecurrentState=State.PENDING;publicvoidhandleEvent(Eventevent){switch(currentState){casePENDING:if(event==Event.PAY){currentState=State.PAID;System.out.println("支付成功,状态变为 PAID");}else{System.out.println("无效操作");}break;casePAID:if(event==Event.SHIP){currentState=State.SHIPPED;System.out.println("发货成功,状态变为 SHIPPED");}else{System.out.println("无效操作");}break;caseSHIPPED:if(event==Event.DELIVER){currentState=State.DELIVERED;System.out.println("收货成功,状态变为 DELIVERED");}else{System.out.println("无效操作");}break;caseDELIVERED:System.out.println("订单已完成,无操作");break;default:System.out.println("未知状态");}}publicstaticvoidmain(String[]args){OrderEnumorder=newOrderEnum();order.handleEvent(Event.PAY);// 支付成功order.handleEvent(Event.SHIP);// 发货成功order.handleEvent(Event.DELIVER);// 收货成功}}

扩展提示:如果动作复杂,可以在 case 中调用私有方法执行具体逻辑。

方式二:状态模式(State Pattern,经典 OOP 方式)

使用接口定义状态行为,每个状态一个实现类。订单类持有一个状态对象,根据事件委托给当前状态处理。

优点:每个状态独立类,易扩展(新增状态只需加类);符合开闭原则(修改关闭,扩展开放)。
缺点:类爆炸(状态多时类文件多);初始代码量大。
适用:中等复杂场景,企业级系统。

// 状态接口interfaceOrderState{voidpay(OrderContextcontext);voidship(OrderContextcontext);voiddeliver(OrderContextcontext);}// 上下文类(订单)classOrderContext{privateOrderStatecurrentState;publicOrderContext(){currentState=newPendingState();// 初始状态}publicvoidsetState(OrderStatestate){this.currentState=state;}publicvoidpay(){currentState.pay(this);}publicvoidship(){currentState.ship(this);}publicvoiddeliver(){currentState.deliver(this);}}// 具体状态类(Pending)classPendingStateimplementsOrderState{@Overridepublicvoidpay(OrderContextcontext){System.out.println("支付成功,状态变为 PAID");context.setState(newPaidState());}@Overridepublicvoidship(OrderContextcontext){System.out.println("请先支付");}@Overridepublicvoiddeliver(OrderContextcontext){System.out.println("无效操作");}}// PaidState(类似,其他状态类省略)classPaidStateimplementsOrderState{@Overridepublicvoidpay(OrderContextcontext){System.out.println("已支付,无需重复");}@Overridepublicvoidship(OrderContextcontext){System.out.println("发货成功,状态变为 SHIPPED");context.setState(newShippedState());}@Overridepublicvoiddeliver(OrderContextcontext){System.out.println("无效操作");}}// ShippedState 和 DeliveredState 类似...publicclassOrderStatePattern{publicstaticvoidmain(String[]args){OrderContextorder=newOrderContext();order.pay();// 支付成功order.ship();// 发货成功order.deliver();// 无效操作(需实现 ShippedState)}}

扩展提示:每个状态类可以持有上下文数据;用枚举管理状态类实例(单例)。

方式三:表驱动法(使用 Map 的策略模式)

用 Map 映射“当前状态 + 事件”到“下一个状态 + 动作”。适合状态转换规则明确的场景。

优点:配置化、易修改(Map 可以从配置文件加载);无 switch,无多类。
缺点:动作复杂时需用 Lambda 或函数接口;可读性稍差。
适用:规则多、需动态配置的系统(如游戏 AI、流程引擎)。

importjava.util.HashMap;importjava.util.Map;importjava.util.function.Consumer;publicclassOrderTableDriven{enumState{PENDING,PAID,SHIPPED,DELIVERED}enumEvent{PAY,SHIP,DELIVER}privateStatecurrentState=State.PENDING;// 动作接口(Consumer 消费上下文,这里简化无上下文)privatestaticclassTransition{StatenextState;Consumer<Void>action;Transition(Statenext,Consumer<Void>act){nextState=next;action=act;}}privatefinalMap<State,Map<Event,Transition>>stateMachine=newHashMap<>();publicOrderTableDriven(){// 配置状态机表Map<Event,Transition>pendingMap=newHashMap<>();pendingMap.put(Event.PAY,newTransition(State.PAID,v->System.out.println("支付成功")));stateMachine.put(State.PENDING,pendingMap);Map<Event,Transition>paidMap=newHashMap<>();paidMap.put(Event.SHIP,newTransition(State.SHIPPED,v->System.out.println("发货成功")));stateMachine.put(State.PAID,paidMap);Map<Event,Transition>shippedMap=newHashMap<>();shippedMap.put(Event.DELIVER,newTransition(State.DELIVERED,v->System.out.println("收货成功")));stateMachine.put(State.SHIPPED,shippedMap);// DELIVERED 无转换stateMachine.put(State.DELIVERED,newHashMap<>());}publicvoidhandleEvent(Eventevent){Map<Event,Transition>transitions=stateMachine.get(currentState);if(transitions==null||!transitions.containsKey(event)){System.out.println("无效操作");return;}Transitiontrans=transitions.get(event);trans.action.accept(null);// 执行动作currentState=trans.nextState;}publicstaticvoidmain(String[]args){OrderTableDrivenorder=newOrderTableDriven();order.handleEvent(Event.PAY);// 支付成功order.handleEvent(Event.SHIP);// 发货成功order.handleEvent(Event.DELIVER);// 收货成功}}

扩展提示:动作可以用 Function 或 Runnable;Map 可以从 JSON/YAML 加载,实现配置驱动。

总结与选择建议
  • 方式一(枚举 + switch):入门级,适合小状态机(<5状态)。
  • 方式二(状态模式):中高级,适合复杂动作(每个状态有独立逻辑)。
  • 方式三(表驱动):高级,适合规则多、需配置化的系统。

三种方式都比 if-else 优雅,选择基于项目复杂度。实际开发中,可结合 Spring StateMachine 框架(企业级状态机库)进一步简化。

如果你想看更多代码细节、测试用例,或对比其他方式(如策略模式变体),告诉我你的需求,我继续展开~ 😊

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/7 4:19:53

适合初学者的C语言编程工具推荐,类似WinTC的轻量IDE

对于C语言初学者来说&#xff0c;选择合适的学习工具至关重要。类似WinTC这样的集成开发环境&#xff0c;专为教学场景设计&#xff0c;简化了编程环境配置的复杂性&#xff0c;让学习者能够专注于语法和逻辑本身。这类工具通常界面简洁、功能聚焦&#xff0c;是入门阶段的理想…

作者头像 李华
网站建设 2026/3/10 1:16:20

C++ 模板初级:函数 / 类模板 + 实例化 + 匹配原则全讲透

C 模板初级&#xff1a;函数模板、类模板、实例化、匹配原则全讲透 下面是用最直白、最结构化的方式&#xff0c;把 C 模板最核心的初级内容讲清楚&#xff0c;适合“刚接触模板不久&#xff0c;但已经能写简单函数和类”的学习者。 1. 模板到底在解决什么问题&#xff1f; …

作者头像 李华
网站建设 2026/3/5 1:31:44

计算机SSM毕设实战-基于SSM架构的物业管理系统的设计与实现基于ssm的城市生活e家平台的设计与开发【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/3/7 1:43:50

SSM毕设项目推荐-基于ssm的城市生活e家平台的设计与开发基于ssm+vue“e家”智慧物业系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/3/5 1:31:39

构建区域创新生态,破解科技成果转化难题

在当今快速发展的科技时代&#xff0c;科技创新已成为推动社会进步和经济发展的核心动力。然而&#xff0c;在实际操作中&#xff0c;科技成果转化却面临着诸多瓶颈问题。科技成果供需信息不对称、转化渠道不畅、专业化服务能力不足等现象普遍存在。与此同时&#xff0c;作为科…

作者头像 李华