Java 23 种设计模式:从踩坑到精通 | 番外:状态 vs 策略 —— if-else 消除的两条路,你走对了吗?

Java 23 种设计模式:从踩坑到精通 | 番外:状态 vs 策略 ------ if-else 消除的两条路,你走对了吗?

摘要 :状态模式和策略模式都能消除 if-else,都通过多态将不同逻辑封装到独立类中。但它们的核心区别在于谁来决定切换------状态模式中状态对象自己决定下一步流转,策略模式中客户端主动选择算法。本文从订单状态流转和促销策略计算两个实战场景出发,结合代码对比、UML 分析和 Spring State Machine 源码,帮你彻底分清这对"行为型双胞胎"。
🗺️ 本文阅读地图(3 分钟速览)

  • 为什么状态和策略都能消除 if-else?它们到底像在哪里?
  • 一张表看懂:意图、切换方式、上下文感知的全面对比
  • 手写订单状态机 vs 促销策略引擎,感受差异
  • Spring State Machine 如何体现代状态模式?
  • 面试必问:"状态模式和策略模式怎么区分?能配合使用吗?"
    📖 《Java 23 种设计模式:从踩坑到精通》

开篇:系列介绍与目录 | 当前:番外 · 状态 vs 策略

🔗 返回系列总目录


文章目录

  • [Java 23 种设计模式:从踩坑到精通 | 番外:状态 vs 策略 ------ if-else 消除的两条路,你走对了吗?](#Java 23 种设计模式:从踩坑到精通 | 番外:状态 vs 策略 —— if-else 消除的两条路,你走对了吗?)
    • [1. 从"订单处理"和"促销计算"两个场景说起](#1. 从“订单处理”和“促销计算”两个场景说起)
      • [1.1 场景一:订单状态流转(状态模式)](#1.1 场景一:订单状态流转(状态模式))
      • [1.2 场景二:促销策略计算(策略模式)](#1.2 场景二:促销策略计算(策略模式))
    • [2. UML 对比:结构相似,意图不同](#2. UML 对比:结构相似,意图不同)
      • [2.1 状态模式 UML](#2.1 状态模式 UML)
      • [2.2 策略模式 UML](#2.2 策略模式 UML)
    • [3. 三大核心区别](#3. 三大核心区别)
    • [4. 深入理解:Spring State Machine 如何体现代状态模式](#4. 深入理解:Spring State Machine 如何体现代状态模式)
    • [5. 状态和策略能配合使用吗?](#5. 状态和策略能配合使用吗?)
    • [6. 面试必问 + 追问连环炮](#6. 面试必问 + 追问连环炮)
    • [🧭 《Java 23 种设计模式:从踩坑到精通》快速导航](#🧭 《Java 23 种设计模式:从踩坑到精通》快速导航)

1. 从"订单处理"和"促销计算"两个场景说起

1.1 场景一:订单状态流转(状态模式)

订单有"待支付"、"已支付"、"已发货"、"已完成"等状态。每个状态下,用户能执行的操作不同。如果用 if-else 判断当前状态再执行操作,代码会迅速膨胀。我们选择状态模式

java 复制代码
// 状态模式:状态对象自己决定下一步
public class PaidState implements OrderState {
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已发货");
        context.setState(new ShippedState());  // 状态对象自己决定切换到"已发货"
    }
    @Override
    public void cancel(OrderContext context) {
        throw new IllegalStateException("已支付订单无法取消,请申请退款");
    }
}

1.2 场景二:促销策略计算(策略模式)

促销有"满减"、"打折"、"立减"等多种算法。用户下单时需要根据促销类型计算价格。我们选择策略模式

java 复制代码
// 策略模式:客户端选择策略
Order order = new Order(500);
order.setPromotionStrategy(new FullReductionStrategy());  // 客户端主动选择
double price = order.checkout();

关键差异已浮现

  • 状态模式中,PaidState 自己在 ship() 方法中调用 context.setState() 切换到下一个状态,状态对象控制流转
  • 策略模式中,客户端调用 setPromotionStrategy() 传入具体策略,客户端控制选择

2. UML 对比:结构相似,意图不同

2.1 状态模式 UML

2.2 策略模式 UML

UML 的关键差异

  • 状态模式的 Context 提供 setState() 方法,由状态对象在 handle() 中调用;
  • 策略模式的 Context 提供 setStrategy() 方法,由客户端调用;
  • 状态类之间通常有明确的转换关系,策略类之间完全独立。

3. 三大核心区别

对比维度 状态模式 策略模式
意图 让对象的行为随内部状态自动改变 封装一系列算法,使其可相互替换
谁决定切换 状态对象自己决定何时切换到另一个状态 客户端显式选择策略
上下文感知 状态对象持有 Context 引用,可调用 context.setState() 策略对象通常不知道 Context 的存在
类间关系 状态类之间有明确的转换关系(如待支付→已支付→已发货) 策略类之间完全独立,互不感知
典型应用 订单状态机、线程状态、工单流转 支付方式、排序算法、折扣策略

💡 简单记忆:状态模式是"被动流转"------状态对象自己决定下一步;策略模式是"主动选择"------客户端选择算法。


4. 深入理解:Spring State Machine 如何体现代状态模式

Spring State Machine 是一个专门的状态机框架,它通过配置定义状态和事件,由引擎管理状态流转。这本质上就是状态模式的升级版本。

java 复制代码
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {

    @Override
    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
        states
            .withStates()
            .initial("待支付")
            .state("已支付")
            .state("已发货")
            .end("已完成")
            .end("已取消");
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
        transitions
            .withExternal()
                .source("待支付").target("已支付").event("支付")
            .and()
            .withExternal()
                .source("待支付").target("已取消").event("取消")
            .and()
            .withExternal()
                .source("已支付").target("已发货").event("发货")
            .and()
            .withExternal()
                .source("已发货").target("已完成").event("确认收货");
    }
}

为什么是状态模式?

  • 状态的流转由状态机引擎控制(类比状态对象自己决定下一步);
  • 每个状态下的合法操作通过配置明确(类比状态对象内部的判断逻辑);
  • 外部只需触发事件,无需关心当前处于哪个状态(类比客户端只调用 context.request())。

5. 状态和策略能配合使用吗?

当然可以。 订单状态决定"什么时候该结算",促销策略决定"用什么算法结算"。

java 复制代码
// 在"已支付"状态中,调用策略模式计算最终价格
public class PaidState implements OrderState {
    @Override
    public void checkout(OrderContext context, PromotionStrategy strategy) {
        double finalPrice = strategy.calculate(context.getOrder());
        context.setTotalPrice(finalPrice);
        // ... 完成结算,进入下一状态
    }
}

💡 组合方式:状态决定"什么时候做",策略决定"怎么做"。两者解耦,各自独立变化。

6. 面试必问 + 追问连环炮

基础必问

  • 状态模式和策略模式的区别?
    👉 状态模式状态对象自己决定切换(被动流转),策略模式由客户端显式选择(主动替换)。
  • JDK 哪里用了状态模式?
    👉 线程的状态转换(NEW → RUNNABLE → WAITING → BLOCKED → TERMINATED)。

面试官追问

  • "状态模式中状态类为什么要持有上下文引用?"
    👉 以便在需要流转时调用 context.setState() 切换到新状态。策略模式不需要,因为策略只关心算法本身。
  • "如果状态转换逻辑很复杂,状态类会膨胀怎么办?"
    👉 使用状态机框架(如 Spring State Machine)将状态、事件、转换规则配置化,避免手写大量状态类。
  • "状态模式和策略模式能配合使用吗?"
    👉 可以。状态决定"何时执行",策略决定"如何执行"。如订单状态决定该结算了,策略决定用满减还是打折。
  • "策略模式如何消除 if-else?"
    👉 将每个分支算法封装为独立的策略类,通过多态调用。但策略的选择本身可能仍需一个 if-else 或工厂来根据条件创建具体策略实例------这部分可以交给策略工厂处理。

🎉 恭喜:如果你能立刻说出"状态自己决定流转,策略由客户端选择",并画出状态流转图与策略对比图,你已经掌握了行为型模式中最核心的区分点。
💡 延伸阅读 :本文是状态模式与策略模式的深度对比。如果你想先了解每种模式的完整原理、UML、代码实现和面试题,可以先阅读正篇------状态模式:if-else 满天飞?让状态自己决定行为策略模式:算法族的封装与切换,告别 if-else,再回来看这篇对比,效果更佳。

🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。

📦 福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
📌 除了设计模式,我也在深挖智能物流实战 (WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。

相关推荐
等什么秋1 小时前
idea2024下载
java·ide·intellij-idea
学计算机的计算基1 小时前
LeetCode 图论四题精讲:BFS、拓扑排序、Trie 树的模板与优化
java·笔记·算法
浩瀚地学1 小时前
【面试算法笔记】0202-链表-基本功能实现
java·经验分享·笔记·算法·面试
3DVisionary2 小时前
如何用单目高速DIC把“看不见“的振动变成“数得清“的数据
java·spring boot·python·数码相机·微小振动·精密件·单目高速dic
tkevinjd2 小时前
416分割等和子集
java·python·算法·leetcode·职场和发展
xiaotie10052 小时前
给deerflow2.0增加模型Token 使用数量显示的功能
状态模式
qq_452396232 小时前
第三篇:《Jenkins Pipeline as Code:Declarative Pipeline 深度实战》
java·servlet·jenkins
再让我睡两分钟2 小时前
【无标题】
android·java·数据库·人工智能·prompt·ai应用开发
折哥的程序人生 · 物流技术专研2 小时前
Java 23 种设计模式:从踩坑到精通 | 番外:工厂方法 vs 抽象工厂 —— 从单产品到产品族,架构如何演进?
java·spring·java面试·抽象工厂·工厂方法·java设计模式·从踩坑到精通