文章目录
- [0. 个人感悟](#0. 个人感悟)
- [1. 概念](#1. 概念)
- [2. 适配场景](#2. 适配场景)
-
- [2.1 适合的场景](#2.1 适合的场景)
- [2.2 常见场景举例](#2.2 常见场景举例)
- [3. 实现方法](#3. 实现方法)
-
- [3.1 实现思路](#3.1 实现思路)
- [3.2 UML类图](#3.2 UML类图)
- [3.3 代码示例](#3.3 代码示例)
- [4. 优缺点](#4. 优缺点)
-
- [4.1 优点](#4.1 优点)
- [4.2 缺点](#4.2 缺点)
0. 个人感悟
- 状态模式旨在将状态封装成独立的类,各个状态子类完成不同的行为,状态改变时切换到不同的子类
- 我理解是将状态x行为,按照状态维度展开。对比传统的按行为展开,会更符合面向对象,代码会更清晰,少许多if-else判断
- 实际工作中遇到的类似场景还比较多,比如常见的工作流程流转业务,对于不同的状态有不同的操作,业务也会复杂很多,比如权限控制等等
- 状态的切换可以由状态类来切换,也可以上下文管理,建议实际工作中抽取出专门的类进行管理,降低耦合
1. 概念
英文定义 (《设计模式:可复用面向对象软件的基础》)
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
中文翻译
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
理解
- 状态模式是一种行为型设计模式,核心思想是将状态封装为独立的类
- 将对象在不同状态下的行为委托给当前状态对象执行,而非在对象内部使用大量条件判断
- 当对象状态改变时,实际上是通过切换到不同的状态类实例来改变行为
- 符合"开闭原则"------新增状态无需修改现有代码,只需添加新的状态类
- 状态转换逻辑可以分散在各个状态类中,也可以集中在上下文类中管理
2. 适配场景
2.1 适合的场景
- 对象行为随状态改变而改变:对象需要根据当前状态执行不同操作
- 复杂的条件分支逻辑:代码中包含大量与对象状态相关的条件语句(if-else或switch-case)
- 状态转换逻辑固定且明确:状态之间的转换有明确的规则和条件
- 状态数量相对稳定:状态数量不会频繁变化,避免因状态过多导致类爆炸
2.2 常见场景举例
- 订单系统:订单的待支付、已支付、已发货、已完成、已取消等状态
- 工作流引擎:审批流程中的草稿、待审批、已审批、已驳回等状态
- 游戏开发:游戏角色的站立、行走、奔跑、跳跃、攻击、受伤等状态
- 网络连接:TCP连接中的CLOSED、LISTEN、SYN_SENT、ESTABLISHED等状态
- UI组件:按钮的启用、禁用、悬停、按下等交互状态
- 交通信号灯:红灯、黄灯、绿灯的状态切换
3. 实现方法
3.1 实现思路
- 定义状态接口:声明所有状态类必须实现的方法,这些方法对应上下文类中的各种操作
- 实现具体状态类:为每个状态创建独立的类,实现状态接口,封装该状态下的具体行为
- 创建上下文类 :
- 维护当前状态对象的引用
- 将客户端请求委托给当前状态对象处理
- 提供设置状态的方法(状态转换)
- 管理状态转换 :
- 可以在上下文类中集中管理(策略模式风格)
- 也可以在各个状态类中分散管理(状态模式典型风格)
- 客户端使用:客户端通过上下文类与状态机交互,无需关心当前具体状态
3.2 UML类图

角色说明:
- Context(上下文):定义客户端感兴趣的接口,维护一个ConcreteState子类的实例
- State(状态接口):定义一个接口以封装与Context的一个特定状态相关的行为
- ConcreteState(具体状态):每个子类实现一个与Context的一个状态相关的行为
3.3 代码示例
背景
以自动咖啡机为例
- 正常流程行为有投币、选咖啡、制作咖啡、取咖啡,异常行为有补充咖啡豆
- 正常状态有等待投币、等待选择咖啡、已选择咖啡、咖啡已制作完成,异常状态为咖啡豆不足
行为接口
java
public interface ICoffeeMachineState {
/**
* @param machine 咖啡机上下文
* @description 投币
* @author bigHao
* @date 2026/1/28
**/
void insertCoin(CoffeeMachine machine);
/**
* @param machine 咖啡机上下文
* @description 选择咖啡
* @author bigHao
* @date 2026/1/28
**/
void selectCoffee(CoffeeMachine machine);
/**
* @param machine 咖啡机上下文
* @description 制作咖啡
* @author bigHao
* @date 2026/1/28
**/
void dispenseCoffee(CoffeeMachine machine);
/**
* @param machine 咖啡机上下文
* @description 取走coffee
* @author bigHao
* @date 2026/1/28
**/
void takeCoffee(CoffeeMachine machine);
/**
* @param machine 咖啡机上下文
* @param amount 豆子数量
* @description 补充豆子
* @author bigHao
* @date 2026/1/28
**/
void refill(CoffeeMachine machine, int amount);
}
行为实现类族
java
\\ 等待投币
public class WaitingForCoinState implements ICoffeeMachineState {
@Override
public void insertCoin(CoffeeMachine machine) {
System.out.println("硬币已投入,请选择咖啡");
machine.setState(new WaitingForSelectState());
}
@Override
public void selectCoffee(CoffeeMachine machine) {
System.out.println("请先投币");
}
@Override
public void dispenseCoffee(CoffeeMachine machine) {
System.out.println("请先投币并选择咖啡");
}
@Override
public void takeCoffee(CoffeeMachine machine) {
System.out.println("请先投币并选择咖啡");
}
@Override
public void refill(CoffeeMachine machine, int amount) {
machine.addCoffeeBeans(amount);
System.out.println("添加了 " + amount + " 克咖啡豆");
}
}
\\ 等待选择coffee
public class WaitingForSelectState implements ICoffeeMachineState {
@Override
public void insertCoin(CoffeeMachine machine) {
System.out.println("硬币已投入,请选择咖啡");
machine.setState(new WaitingForSelectState());
}
@Override
public void selectCoffee(CoffeeMachine machine) {
System.out.println("咖啡已选择,请按制作按钮");
machine.setState(new CoffeeSelectedState());
}
@Override
public void dispenseCoffee(CoffeeMachine machine) {
System.out.println("硬币已投入,请选择咖啡");
}
@Override
public void takeCoffee(CoffeeMachine machine) {
System.out.println("硬币已投入,请选择咖啡");
}
@Override
public void refill(CoffeeMachine machine, int amount) {
machine.addCoffeeBeans(amount);
System.out.println("添加了 " + amount + " 克咖啡豆");
}
}
\\ coffee已选择
public class CoffeeSelectedState implements ICoffeeMachineState {
@Override
public void insertCoin(CoffeeMachine machine) {
System.out.println("已投币,请按制作按钮");
}
@Override
public void selectCoffee(CoffeeMachine machine) {
System.out.println("咖啡已选择,请按制作按钮");
}
@Override
public void dispenseCoffee(CoffeeMachine machine) {
if (machine.getCoffeeBeans() >= 10) {
System.out.println("正在制作咖啡...");
machine.reduceCoffeeBeans(10);
machine.setState(new CoffeeReadyState());
} else {
System.out.println("咖啡豆不足,请联系工作人员");
machine.setState(new OutOfBeanState());
}
}
@Override
public void takeCoffee(CoffeeMachine machine) {
System.out.println("咖啡已选择,请按制作按钮");
}
@Override
public void refill(CoffeeMachine machine, int amount) {
machine.addCoffeeBeans(amount);
System.out.println("添加了 " + amount + " 克咖啡豆");
}
}
\\ coffee已制作
public class CoffeeReadyState implements ICoffeeMachineState {
@Override
public void insertCoin(CoffeeMachine machine) {
System.out.println("请取走您的咖啡后再投币");
}
@Override
public void selectCoffee(CoffeeMachine machine) {
System.out.println("请取走您的咖啡后再选择");
}
@Override
public void dispenseCoffee(CoffeeMachine machine) {
System.out.println("咖啡已准备好,请取走");
}
@Override
public void takeCoffee(CoffeeMachine machine) {
System.out.println("取走coffee,谢谢惠顾");
machine.setState(new WaitingForCoinState());
}
@Override
public void refill(CoffeeMachine machine, int amount) {
machine.addCoffeeBeans(amount);
System.out.println("添加了 " + amount + " 克咖啡豆");
}
}
\\ 咖啡豆不足
public class OutOfBeanState implements ICoffeeMachineState {
@Override
public void insertCoin(CoffeeMachine machine) {
System.out.println("咖啡豆不足,无法制作咖啡");
}
@Override
public void selectCoffee(CoffeeMachine machine) {
System.out.println("咖啡豆不足,无法制作咖啡");
}
@Override
public void dispenseCoffee(CoffeeMachine machine) {
System.out.println("咖啡豆不足,无法制作咖啡");
}
@Override
public void takeCoffee(CoffeeMachine machine) {
System.out.println("咖啡豆不足,无法制作咖啡");
}
@Override
public void refill(CoffeeMachine machine, int amount) {
machine.addCoffeeBeans(amount);
System.out.println("添加了 " + amount + " 克咖啡豆");
if (machine.getCoffeeBeans() >= 10) {
machine.setState(new CoffeeSelectedState());
}
}
}
测试
java
public class Client {
static void main() {
// 正常流程
System.out.println("=======正常流程示例=======");
CoffeeMachine coffeeMachine = new CoffeeMachine(11);
printState(coffeeMachine);
System.out.println("===投币===");
coffeeMachine.insertCoin();
printState(coffeeMachine);
System.out.println("===选择coffee===");
coffeeMachine.selectCoffee();
printState(coffeeMachine);
System.out.println("===制作coffee===");
coffeeMachine.dispenseCoffee();
printState(coffeeMachine);
System.out.println("===取走coffee===");
coffeeMachine.takeCoffee();
printState(coffeeMachine);
System.out.println("=======豆子不足流程示例=======");
// 异常情况 咖啡豆不足
coffeeMachine.insertCoin();
printState(coffeeMachine);
coffeeMachine.selectCoffee();
printState(coffeeMachine);
System.out.println("===咖啡豆不足===");
coffeeMachine.dispenseCoffee();
printState(coffeeMachine);
// 补充咖啡豆
System.out.println("===补充coffee===");
coffeeMachine.refill(100);
printState(coffeeMachine);
System.out.println("===制作coffee===");
coffeeMachine.dispenseCoffee();
printState(coffeeMachine);
System.out.println("===取走coffee===");
coffeeMachine.takeCoffee();
printState(coffeeMachine);
}
public static void printState(CoffeeMachine coffeeMachine) {
System.out.println(STR."当前状态: \{coffeeMachine.getCurrentState()}");
}
}
输出
=======正常流程示例=======
当前状态: WaitingForCoinState
===投币===
硬币已投入,请选择咖啡
当前状态: WaitingForSelectState
===选择coffee===
咖啡已选择,请按制作按钮
当前状态: CoffeeSelectedState
===制作coffee===
正在制作咖啡...
当前状态: CoffeeReadyState
===取走coffee===
取走coffee,谢谢惠顾
当前状态: WaitingForCoinState
=======豆子不足流程示例=======
硬币已投入,请选择咖啡
当前状态: WaitingForSelectState
咖啡已选择,请按制作按钮
当前状态: CoffeeSelectedState
===咖啡豆不足===
咖啡豆不足,请联系工作人员
当前状态: OutOfBeanState
===补充coffee===
添加了 100 克咖啡豆
当前状态: CoffeeSelectedState
===制作coffee===
正在制作咖啡...
当前状态: CoffeeReadyState
===取走coffee===
取走coffee,谢谢惠顾
当前状态: WaitingForCoinState
4. 优缺点
4.1 优点
- 单一职责原则:将与特定状态相关的代码放在独立的类中
- 开闭原则:新增状态无需修改现有状态类或上下文类
- 消除复杂条件判断:避免使用大量的if-else或switch-case语句
- 提高可读性:状态转换逻辑清晰,代码结构更易理解
- 状态管理集中:所有状态相关的代码集中在状态类中,便于维护
4.2 缺点
- 类数量增加:每个状态都需要一个类,状态过多会导致类爆炸
- 状态转换逻辑分散:如果转换逻辑在各状态类中,可能导致逻辑分散难以跟踪
- 上下文与状态耦合:状态类需要了解上下文类的接口,增加了耦合度
- 性能开销:状态切换涉及对象创建和销毁,可能带来额外开销
参考: