跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

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

状态模式通过封装状态行为消除复杂条件判断。本文对比经典状态模式、枚举轻量实现及 Spring StateMachine 框架,展示如何重构电商订单流程中的 if-else 嵌套逻辑。方案涵盖面向对象设计到配置化框架,帮助开发者提升代码可维护性与扩展性。

菩提发布于 2026/3/30更新于 2026/9/860 浏览
Java 状态机实战:三种方式优雅消除 if-else 嵌套

Java 状态机详解 —— 用状态模式优雅消灭 if-else 嵌套

在日常 Java 开发中,我们常常遇到这样的情况:不同的状态有不同的处理逻辑,状态之间会相互切换,不同状态下执行的动作可能完全不同。这时,如果我们用 if-else 或 switch-case 来写,代码很容易变得臃肿难维护。

比如处理订单状态时,常见的写法是这样的:

if(status == 0) { // 待支付逻辑
    // ...
} else if(status == 1) { // 已支付逻辑
    // ...
} else if(status == 2) { // 已发货逻辑
    // ...
}

这种写法的问题:

  • 逻辑分支多,扩展性差
  • 新增状态时,需要修改原有代码(违反开闭原则)
  • 状态切换逻辑容易分散在各个 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("订单已取消");
            }
        }   (status == ) {
             (.equals(action)) {
                System.out.println();
            }
        }   (status == ) {
             (.equals(action)) {
                System.out.println();
            }
        }
    }
}
else
if
1
if
"ship"
"订单已发货"
else
if
2
if
"confirm"
"订单已完成"

又或者是这样的:

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 的轻量状态机实现

这里再升级一下,使用 枚举 + Map 的轻量状态机实现。这种写法相比经典状态模式,代码量更少,适合状态数不多、且状态逻辑相对简单的场景。

这种写法的核心思想是:

用枚举类定义所有状态 每个状态实现自己的行为逻辑 通过 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. Java 状态机详解 —— 用状态模式优雅消灭 if-else 嵌套
  2. 1. 复现传统 if-else 实现的业务场景问题
  3. 2. 用状态机模式改造
  4. 2.1 定义状态接口
  5. 2.2 创建上下文类
  6. 2.3 定义具体状态类
  7. 2.4 测试使用
  8. 3. 枚举 + Map 的轻量状态机实现
  9. 3.1 定义状态枚举
  10. 3.2 配置上下文类
  11. 3.3 测试使用
  12. 4. 使用 Spring StateMachine 实现订单状态机
  13. 4.1 依赖引入
  14. 4.2 定义状态与事件枚举
  15. 4.3 配置状态机
  16. 4.4 测试代码
  17. 5. 对比三种方案
  18. 6. 总结

更多推荐文章

查看全部
  • 预训练语言模型与 BERT 实战应用详解
  • Microi 吾码低代码平台技术架构与集成实践
  • AI 赋能产品经理:工作流提效与职业转型实战
  • MC.JS WEBMC1.8 实战:构建在线多人沙盒游戏
  • Kimi2.5 核心技术:注意力残差
  • Java MD5 加密算法原理与实现
  • 双指针算法:快慢指针判断快乐数
  • 前端错误处理实战:try/catch 与 Promise 用法
  • C++ 哈希表核心机制:unordered 系列容器、位图与布隆过滤器实战
  • CentOS 7 安装 Nginx
  • 基于 Web 的远程文件管理系统设计与实现开题答辩记录
  • EgoPoseFormer v2:AR/VR 第一视角人体动作捕捉技术解析
  • Diffusion Transformer (DiT) 详解:从 U-Net 到 ViT,应用于视频生成与机器人动作预测
  • Java 大数据在智能家居能源消耗趋势预测与节能策略优化中的应用
  • AI 无人机智慧巡检平台架构与功能解析
  • PPO-VLA:强化学习如何提升机器人泛化能力
  • ToClaw 评测:不只是炫技,更是易用的桌面 AI 助手
  • Clawdbot 部署指南:反向代理与 WebAuth 安全配置
  • VSCode 搭建 Java + Maven 开发环境实战指南
  • 高校 AIGC 检测新规解读:AI 率合格标准与应对策略

相关免费在线工具

  • 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

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online