跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaPayjava

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

综述由AI生成针对 Java 开发中复杂的条件判断逻辑,通过电商订单场景演示了三种状态机实现方案。首先分析传统 if-else 嵌套的维护痛点,随后分别展示经典状态模式、枚举状态机及 Spring StateMachine 框架的具体落地代码。对比三者优缺点后,建议根据业务复杂度选择合适方案,旨在提升代码可读性与扩展性,避免违反开闭原则。

狂少发布于 2026/3/17更新于 2026/6/516 浏览
Java 状态机详解:三种实现方式优雅消除 if-else 嵌套

状态模式示意图

在日常 Java 开发中,我们常常遇到这样的场景:不同的业务状态对应不同的处理逻辑,且状态之间会相互切换。如果直接使用 if-else 或 switch-case 来编写,代码很容易变得臃肿难维护。

为什么使用状态模式消除 if-else?

当状态增多时,传统的条件判断写法存在明显问题:

  • 逻辑分支多,扩展性差
  • 新增状态时需要修改原有代码(违反开闭原则)
  • 状态切换逻辑分散,不够集中

使用状态机(State Machine)可以解决上述问题,具备以下优点:

  • 消除复杂的条件判断语句
  • 提高代码可读性和可维护性
  • 使状态转换逻辑更加清晰
  • 符合开闭原则,易于扩展新状态

1. 复现传统 if-else 实现的业务场景问题

假设有一个电商订单系统,订单状态包括:待支付、已支付、已发货、已完成。订单流转路径为:待支付 → 支付 → 发货 → 完成,同时支持在待支付状态下取消订单。

常见的传统实现代码如下:

public class OrderServiceIfElse {
    public void handle(int status, String action) {
        if (status == 0) {
            if ("pay".equals(action)) {
                System.out.println("订单已支付");
            } else if ("cancel".equals(action)) {
                System.out.println("订单已取消");
            }
        } else if (status == 1) {
            if ("ship".equals(action)) {
                System.out.println("订单已发货");
            }
        } else if (status == 2) {
            if ("confirm".equals(action)) {
                System.out.println("订单已完成");
            }
        }
    }
}

或者另一种常见写法:

public class Order {
    private String state;
    
    public void process() {
        if ("NEW".equals(state)) {
            System.out.println("处理新订单");
            state = "PROCESSING";
        } else if ("PROCESSING".equals(state)) {
            System.out.println("订单处理中");
            state = "SHIPPED";
        } else if ("SHIPPED".equals(state)) {
            System.out.println("订单已发货");
            state = "DELIVERED";
        } else if ("DELIVERED".equals(state)) {
            System.out.println("订单已完成");
        } else {
            throw new IllegalStateException("无效订单状态:" + state);
        }
    }
}

无论是哪一种写法,都会面临以下挑战:

  • 当状态增多时,代码变得臃肿难以维护
  • 违反开闭原则,添加新状态需要修改现有代码
  • 状态转换逻辑分散在多个地方
  • 难以跟踪状态转换规则

2. 用状态模式改造

下面我们使用状态模式重构上述订单处理流程。

2.1 定义状态接口

首先定义一个统一的状态接口,声明所有可能的操作。

public interface OrderState {
    void pay(OrderContext context);
    void ship(OrderContext context);
    void confirm(OrderContext context);
    void cancel(OrderContext context);
}

2.2 创建上下文类

上下文类负责持有当前状态,并将请求委托给当前状态对象。

public class OrderContext {
    private OrderState state;

    public OrderContext(OrderState state) {
        this.state = state;
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    public void pay() {
        state.pay(this);
    }

    public void ship() {
        state.ship(this);
    }

    public void confirm() {
        state.confirm(this);
    }

    public void cancel() {
        state.cancel(this);
    }
}

2.3 定义具体状态类

每个具体状态类实现接口,并封装该状态下的行为逻辑及状态转换。

// 待支付状态
public class PendingPayState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单支付成功");
        context.setState(new PaidState());
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("请先支付订单");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("请先支付订单");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消");
    }
}

// 已支付状态
public class PaidState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已支付,请勿重复支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已发货");
        context.setState(new ShippedState());
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("订单还未发货");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("已支付订单不能取消");
    }
}

// 已发货状态
public class ShippedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已经发货");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("订单已完成");
        context.setState(new CompletedState());
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("发货后不能取消订单");
    }
}

// 已完成状态
public class CompletedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已完成,无法支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已完成,无法发货");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("订单已完成");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已完成,无法取消");
    }
}

2.4 测试使用

public class StateMachineTest {
    public static void main(String[] args) {
        // 初始状态:待支付
        OrderContext order = new OrderContext(new PendingPayState());
        order.pay();   // 支付
        order.ship();  // 发货
        order.confirm(); // 确认收货
        // 输出:
        // 订单支付成功
        // 订单已发货
        // 订单已完成
    }
}

3. 枚举 + Map 的轻量状态机实现

相比经典状态模式,使用枚举结合方法实现的状态机代码量更少,适合状态数不多、且状态逻辑相对简单的场景。

核心思想:

  • 用枚举类定义所有状态
  • 每个状态实现自己的行为逻辑
  • 直接通过当前状态对象来执行对应方法,避免 if-else

3.1 定义状态枚举

public enum OrderStateEnum {
    PENDING_PAY {
        @Override
        public OrderStateEnum pay() {
            System.out.println("订单支付成功");
            return PAID;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("请先支付订单");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("请先支付订单");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("订单已取消");
            return this;
        }
    },
    PAID {
        @Override
        public OrderStateEnum pay() {
            System.out.println("订单已支付,请勿重复支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("订单已发货");
            return SHIPPED;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("订单还未发货");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("已支付订单不能取消");
            return this;
        }
    },
    SHIPPED {
        @Override
        public OrderStateEnum pay() {
            System.out.println("订单已支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("订单已经发货");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("订单已完成");
            return COMPLETED;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("发货后不能取消订单");
            return this;
        }
    },
    COMPLETED {
        @Override
        public OrderStateEnum pay() {
            System.out.println("订单已完成,无法支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("订单已完成,无法发货");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("订单已完成");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("订单已完成,无法取消");
            return this;
        }
    };

    public abstract OrderStateEnum pay();
    public abstract OrderStateEnum ship();
    public abstract OrderStateEnum confirm();
    public abstract OrderStateEnum cancel();
}

设计说明:

  • 每个状态用一个枚举常量表示
  • 每个枚举常量实现自己的状态切换逻辑
  • 方法返回新的状态枚举,实现状态流转

3.2 配置上下文类

public class OrderContextEnum {
    private OrderStateEnum state;

    public OrderContextEnum(OrderStateEnum state) {
        this.state = state;
    }

    public void pay() {
        state = state.pay();
    }

    public void ship() {
        state = state.ship();
    }

    public void confirm() {
        state = state.confirm();
    }

    public void cancel() {
        state = state.cancel();
    }
}

3.3 测试使用

public class EnumStateMachineTest {
    public static void main(String[] args) {
        OrderContextEnum order = new OrderContextEnum(OrderStateEnum.PENDING_PAY);
        order.pay();   // 支付
        order.ship();  // 发货
        order.confirm(); // 确认收货
    }
}

4. 使用 Spring StateMachine 实现订单状态机

Spring StateMachine 是 Spring 官方提供的状态机框架,支持可配置状态流转、事件驱动、监听器回调等功能,特别适合业务流程复杂、状态多变的场景。

4.1 依赖引入

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>3.2.1</version>
</dependency>

4.2 定义状态与事件枚举

// 订单状态
public enum OrderState {
    PENDING_PAY, // 待支付
    PAID,        // 已支付
    SHIPPED,     // 已发货
    COMPLETED    // 已完成
}

// 触发事件
public enum OrderEvent {
    PAY,      // 支付
    SHIP,     // 发货
    CONFIRM,  // 确认收货
    CANCEL    // 取消订单
}

4.3 配置状态机

import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
import java.util.EnumSet;

@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {

    @Override
    public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception {
        states.withStates()
              .initial(OrderState.PENDING_PAY) // 初始状态
              .states(EnumSet.allOf(OrderState.class)); // 所有状态
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {
        transitions
            .withExternal().source(OrderState.PENDING_PAY).target(OrderState.PAID).event(OrderEvent.PAY).and()
            .withExternal().source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP).and()
            .withExternal().source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.CONFIRM).and()
            .withExternal().source(OrderState.PENDING_PAY).target(OrderState.PENDING_PAY).event(OrderEvent.CANCEL);
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderState, OrderEvent> config) throws Exception {
        config.withConfiguration()
              .listener(new StateMachineListenerAdapter<>() {
                  @Override
                  public void stateChanged(State<OrderState, OrderEvent> from, State<OrderState, OrderEvent> to) {
                      System.out.println("状态切换:" + (from == null ? "无" : from.getId()) + " -> " + to.getId());
                  }
              });
    }
}

4.4 测试代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Component;

@Component
public class OrderStateMachineTest implements CommandLineRunner {

    @Autowired
    private StateMachine<OrderState, OrderEvent> stateMachine;

    @Override
    public void run(String... args) throws Exception {
        stateMachine.start();
        stateMachine.sendEvent(OrderEvent.PAY);
        stateMachine.sendEvent(OrderEvent.SHIP);
        stateMachine.sendEvent(OrderEvent.CONFIRM);
        stateMachine.stop();
    }
}

观察控制台会输出如下:

状态切换:无 -> PENDING_PAY 状态切换:PENDING_PAY -> PAID 状态切换:PAID -> SHIPPED 状态切换:SHIPPED -> COMPLETED

5. 对比三种方案

实现方式优点缺点适用场景
经典状态模式结构清晰,面向对象类文件多,状态多时管理复杂状态多、逻辑复杂的 OO 场景
枚举状态机简洁,集中管理状态多时枚举类太长状态少、逻辑简单
Spring StateMachine功能强大,可配置化需要额外依赖,学习成本高大型系统、状态规则经常变动

经典状态模式适合复杂业务流程,易于模块化管理;枚举 + Map 注册或枚举直接实现行为,适合小型项目或简单状态流转;在 Java 中,枚举天生是单例的,用它实现状态机既简洁又线程安全。

6. 总结

本文详细介绍了使用状态模式消除 if-else 的三种方案:经典状态模式、枚举状态机、Spring StateMachine。从纯手写模式到枚举模式再到框架模式,进行了完整对比和代码演示。当发现自己在编写大量条件语句来处理对象状态时,建议考虑使用状态模式重构您的代码,以提升系统的可维护性和扩展性。

目录

  1. 1. 复现传统 if-else 实现的业务场景问题
  2. 2. 用状态模式改造
  3. 2.1 定义状态接口
  4. 2.2 创建上下文类
  5. 2.3 定义具体状态类
  6. 2.4 测试使用
  7. 3. 枚举 + Map 的轻量状态机实现
  8. 3.1 定义状态枚举
  9. 3.2 配置上下文类
  10. 3.3 测试使用
  11. 4. 使用 Spring StateMachine 实现订单状态机
  12. 4.1 依赖引入
  13. 4.2 定义状态与事件枚举
  14. 4.3 配置状态机
  15. 4.4 测试代码
  16. 5. 对比三种方案
  17. 6. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Docker 部署 OpenClaw 常见问题排查与自定义模型配置
  • C++11 核心特性详解:列表初始化、右值引用与移动语义
  • 基于 Docker 部署 AI 量化分析平台及波浪理论实战
  • Stable Diffusion XL 1.0 免配置方案:灵感画廊 Streamlit UI 定制实战
  • 高校电动车租赁系统设计与实现:SpringBoot+Vue+MySQL
  • Spring Web MVC 入门:从概念到实践
  • Kokoro-TTS跨平台C++移植实战:从Windows到嵌入式终端
  • 集群中继无人机应急通信双层多目标协同优化部署
  • C++ 设计模式详解:创建、结构及行为型核心实现
  • Ubuntu 下 llama.cpp 编译与性能调优实战
  • LeetCode 替换所有问号与提莫攻击解题思路
  • 算法实战:模幂、构造、背包、贪心及堆维护六题精析
  • 企业级图像AIGC技术:Seedream 4.0 模型能力与应用场景
  • AIGC 延迟优化实战:C++ 零拷贝与异步调度方案
  • Python 临床知识问答与检索系统架构设计与实现
  • GPT、LLaMA 与 MOE:自回归模型与混合专家架构演进
  • YOLOv8 车牌定位模型训练与 OpenCV C++ 部署完整指南
  • GESP 2023 年 12 月 C++ 二级认证试题解析(选择题 9-15)
  • C++ STL map 核心解析:从原理到实战应用
  • DeepFace 结合 OpenCV 实现实时情绪分析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online