设计模式之管理状态_Status状态模式_用类保存状态
一、状态模式(State Pattern)
1. 模式概述
状态模式 是一种 行为型设计模式,它允许一个对象在其内部状态改变时 改变其行为,使得对象看起来像是修改了它的类。
核心思想:“状态即对象” —— 把每个状态封装成独立的类,让状态自己决定能做什么、不能做什么。
状态模式 = 状态驱动行为 + 自动流转
- 它不是“替换 if-else”,而是“用对象表达状态”。
类比理解:电梯系统:
- 门开着时不能运行;运行中不能开门;停止后才能开门……
- 每种状态下的操作规则完全不同。
2. 使用场景
状态模式适用于以下情况:
- 对象的行为 依赖于它的状态,且必须在运行时根据状态动态改变;
- 代码中存在 大量与状态相关的条件判断(如
if/else或switch); - 状态转换逻辑 复杂且易变,需要解耦;
- 希望 避免状态判断散落在多个方法中,导致维护困难。
典型应用:
- 订单状态机(待支付 → 已支付 → 已发货 → 已完成);
- 游戏角色状态(站立、奔跑、跳跃、攻击);
- 工作流引擎(草稿 → 审核中 → 已发布 → 已归档);
- 网络连接状态(断开 → 连接中 → 已连接 → 重连)。
在实际开发中:
- 凡是涉及 有限状态机(FSM) 的场景,优先考虑状态模式;
- 订单、审批、设备控制、游戏 AI 都是经典用例;
- 当你发现 switch-case 越来越长,就是重构的好时机。
3. 示例程序:电梯控制系统(优化版)
1)状态接口 LiftState
- 默认抛出 有意义的异常,而非
RuntimeException; - 子类只需重写 允许的操作,其他保持默认。
/**
* 状态接口(State)
*/
public abstract class LiftState {
protected Elevator elevator;
public void setElevator(Elevator elevator) {
this.elevator = elevator;
}
// 所有状态必须实现的操作(可选择性抛出 IllegalStateException)
public void open() { throw new IllegalStateException("当前状态下不允许开门"); }
public void close() { throw new IllegalStateException("当前状态下不允许关门"); }
public void run() { throw new IllegalStateException("当前状态下不允许运行"); }
public void stop() { throw new IllegalStateException("当前状态下不允许停止"); }
}
2)具体状态类
a、开启状态
public class OpeningState extends LiftState {
@Override
public void open() {
System.out.println("【开门】电梯门已开启");
}
@Override
public void close() {
System.out.println("【关门】从开启状态切换到关闭状态");
elevator.setState(new ClosingState());
elevator.close(); // 触发新状态的 close 行为
}
}
b、关闭状态
public class ClosingState extends LiftState {
@Override
public void close() {
System.out.println("【关门】电梯门已关闭");
}
@Override
public void open() {
System.out.println("【开门】从关闭状态切换到开启状态");
elevator.setState(new OpeningState());
elevator.open();
}
@Override
public void run() {
System.out.println("【运行】从关闭状态切换到运行状态");
elevator.setState(new RunningState());
elevator.run();
}
@Override
public void stop() {
System.out.println("【停止】从关闭状态切换到停止状态");
elevator.setState(new StoppingState());
elevator.stop();
}
}
3)运行状态
public class RunningState extends LiftState {
@Override
public void run() {
System.out.println("【运行】电梯正在运行中……");
}
@Override
public void stop() {
System.out.println("【停止】从运行状态切换到停止状态");
elevator.setState(new StoppingState());
elevator.stop();
}
// open/close 保持默认异常
}
4)停止状态
public class StoppingState extends LiftState {
@Override
public void stop() {
System.out.println("【停止】电梯已停止");
}
@Override
public void open() {
System.out.println("【开门】从停止状态切换到开启状态");
elevator.setState(new OpeningState());
elevator.open();
}
@Override
public void run() {
System.out.println("【运行】从停止状态切换到运行状态");
elevator.setState(new RunningState());
elevator.run();
}
// close 保持默认异常
}
3)环境类 Elevator
/**
* 环境类(Context)
*/
public class Elevator {
private LiftState state;
public Elevator() {
// 初始状态设为关闭
setState(new ClosingState());
}
public void setState(LiftState state) {
this.state = state;
this.state.setElevator(this);
}
// 委托给当前状态
public void open() { state.open(); }
public void close() { state.close(); }
public void run() { state.run(); }
public void stop() { state.stop(); }
}
4)客户端测试 Main
public class Main {
public static void main(String[] args) {
Elevator elevator = new Elevator();
elevator.open(); // 关闭 → 开启
System.out.println("--------");
elevator.close(); // 开启 → 关闭
System.out.println("--------");
elevator.run(); // 关闭 → 运行
System.out.println("--------");
elevator.stop(); // 运行 → 停止
System.out.println("--------");
// 尝试非法操作:运行中开门(会抛异常)
try {
elevator.run(); // 停止 → 运行
elevator.open(); // ❌ 运行中不能开门
} catch (IllegalStateException e) {
System.out.println("❌ 操作失败: " + e.getMessage());
}
}
}
输出:
【开门】从关闭状态切换到开启状态
【开门】电梯门已开启
--------
【关门】从开启状态切换到关闭状态
【关门】电梯门已关闭
--------
【运行】从关闭状态切换到运行状态
【运行】电梯正在运行中……
--------
【停止】从运行状态切换到停止状态
【停止】电梯已停止
--------
【运行】从停止状态切换到运行状态
【运行】电梯正在运行中……
❌ 操作失败: 当前状态下不允许开门
5)模式角色
- 所有状态行为 由具体状态类实现;
- 状态切换 由状态自身或 Context 控制;
- 客户端 只与 Context 交互,无需知道具体状态。
| 角色 | 职责 | 示例 |
|---|---|---|
Context(环境类) |
持有当前状态引用,对外提供统一接口,将请求委托给当前状态对象 | Elevator / ProductContext |
State(状态接口) |
定义状态相关行为的公共接口 | LiftState |
ConcreteState(具体状态类) |
实现特定状态下的行为逻辑,可触发状态切换 | OpeningState, RunningState |
4. FQA
1)状态模式 vs 条件分支
| 维度 | 条件分支 | 状态模式 |
|---|---|---|
| 可读性 | 低(逻辑分散) | 高(每个状态职责单一) |
| 可维护性 | 差(新增状态需改多处) | 优(新增状态类即可) |
| 扩展性 | 困难 | 极易 |
| 封装性 | 无 | 高(状态行为内聚) |
| 适用规模 | 状态少、逻辑简单 | 状态多、转换复杂 |
2)模式优点
- 消除庞大的条件语句,代码更清晰;
- 符合开闭原则:新增状态无需修改现有代码;
- 状态行为高内聚,易于测试和复用;
- 状态转换逻辑集中,便于审计和修改。
3)注意事项
- 类数量增加:每个状态需一个类;
- 状态间可能相互依赖,需谨慎设计转换规则;
- 不适合状态极少或转换简单的场景(过度设计)。


