Skip to content

状态模式(State Pattern)笔记

定义

状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。

英文原文定义

The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

核心概念

状态模式通过将不同状态的行为封装到独立的类中,并将状态委托给当前状态对象,使得状态转换更加清晰,避免了复杂的条件判断语句。

主要角色

  1. Context(上下文):维护一个ConcreteState子类的实例,定义当前状态
  2. State(状态接口):定义一个接口,封装与Context的特定状态相关的行为
  3. ConcreteState(具体状态):实现State接口,每个子类实现一个与Context状态相关的行为

优缺点

优点

  • 消除条件语句:用多态代替大量条件判断
  • 单一职责原则:将与特定状态相关的代码放在独立类中
  • 开闭原则:容易新增状态而不修改已有代码
  • 状态转换显式化:使状态转换更加明确和可控
  • 状态对象复用:可以共享无实例变量的状态对象

缺点

  • 类数量增加:每个状态都需要一个类
  • 过度设计风险:简单状态机使用此模式可能增加复杂度
  • 上下文耦合:状态子类可能依赖上下文实现
  • 性能开销:状态转换可能带来额外对象创建开销

解决的问题

状态模式主要解决以下经典问题:

  1. 复杂状态逻辑:对象行为依赖于它的状态,并且必须在运行时根据状态改变行为
  2. 条件语句膨胀:操作中含有大量与对象状态有关的条件语句
  3. 状态转换混乱:当状态转换逻辑分散在多个方法中时
  4. 状态共享需求:当需要多个上下文实例共享状态对象时

实现注意事项

  1. 状态转换位置

    • 由上下文决定(集中管理)
    • 由状态类决定(分散管理)
  2. 状态对象创建

    • 按需创建(每次转换时创建)
    • 预先创建(所有状态单例)
  3. 状态存储

    • 上下文存储全部状态数据
    • 状态对象存储部分状态数据
  4. 线程安全

    • 无状态的状态对象可以共享
    • 有状态的状态对象需要实例化
  5. 初始化状态

    • 确保上下文始终有有效状态
    • 考虑使用Null Object模式处理未知状态

实现变体

  1. 状态驱动转换

    • 状态类知道并决定下一个状态
    • 转换逻辑分散在各状态类中
  2. 表驱动转换

    • 使用转换表定义状态转换规则
    • 更加集中和可配置
  3. 状态模式+享元

    • 无状态的状态对象作为享元共享
    • 适合大量上下文实例场景
  4. 状态模式+组合

    • 构建层次状态结构
    • 支持状态继承和复用

与其他模式的关系

相似模式区分

  1. 策略模式

    • 状态:状态知道其他状态,可触发状态转换
    • 策略:策略通常不知道其他策略
  2. 命令模式

    • 状态:封装与状态相关的行为
    • 命令:封装操作请求
  3. 职责链模式

    • 状态:状态处理请求后可改变上下文状态
    • 职责链:请求沿链传递直到被处理

常见搭配组合

  1. 状态 + 享元:共享无状态的状态对象
  2. 状态 + 单例:状态对象作为单例
  3. 状态 + 组合:构建层次状态机
  4. 状态 + 观察者:状态变化时通知观察者

典型应用场景

  • 订单状态管理(待支付、已支付、已发货等)
  • 工作流引擎
  • 游戏角色状态(站立、行走、奔跑等)
  • TCP连接状态(建立连接、数据传输、关闭连接)
  • 电梯控制系统
  • 自动售货机
  • UI组件状态(启用、禁用、悬停等)

代码示例(电梯状态实现)

java
// 状态接口
interface ElevatorState {
    void openDoors();
    void closeDoors();
    void move();
    void stop();
}

// 具体状态:停止状态
class StoppedState implements ElevatorState {
    private Elevator elevator;
    
    public StoppedState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void openDoors() {
        System.out.println("Opening doors");
        elevator.setState(elevator.getDoorsOpenState());
    }
    
    @Override
    public void closeDoors() {
        System.out.println("Doors already closed");
    }
    
    @Override
    public void move() {
        System.out.println("Starting movement");
        elevator.setState(elevator.getMovingState());
    }
    
    @Override
    public void stop() {
        System.out.println("Already stopped");
    }
}

// 具体状态:门开状态
class DoorsOpenState implements ElevatorState {
    private Elevator elevator;
    
    public DoorsOpenState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void openDoors() {
        System.out.println("Doors already open");
    }
    
    @Override
    public void closeDoors() {
        System.out.println("Closing doors");
        elevator.setState(elevator.getStoppedState());
    }
    
    @Override
    public void move() {
        System.out.println("Cannot move with doors open");
    }
    
    @Override
    public void stop() {
        System.out.println("Already stopped with doors open");
    }
}

// 具体状态:移动状态
class MovingState implements ElevatorState {
    private Elevator elevator;
    
    public MovingState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void openDoors() {
        System.out.println("Cannot open doors while moving");
    }
    
    @Override
    public void closeDoors() {
        System.out.println("Doors already closed while moving");
    }
    
    @Override
    public void move() {
        System.out.println("Already moving");
    }
    
    @Override
    public void stop() {
        System.out.println("Stopping elevator");
        elevator.setState(elevator.getStoppedState());
    }
}

// 上下文:电梯
class Elevator {
    private ElevatorState stoppedState;
    private ElevatorState doorsOpenState;
    private ElevatorState movingState;
    
    private ElevatorState currentState;
    
    public Elevator() {
        stoppedState = new StoppedState(this);
        doorsOpenState = new DoorsOpenState(this);
        movingState = new MovingState(this);
        currentState = stoppedState;
    }
    
    public void setState(ElevatorState state) {
        this.currentState = state;
    }
    
    // 委托给当前状态
    public void openDoors() {
        currentState.openDoors();
    }
    
    public void closeDoors() {
        currentState.closeDoors();
    }
    
    public void move() {
        currentState.move();
    }
    
    public void stop() {
        currentState.stop();
    }
    
    // 获取具体状态
    public ElevatorState getStoppedState() {
        return stoppedState;
    }
    
    public ElevatorState getDoorsOpenState() {
        return doorsOpenState;
    }
    
    public ElevatorState getMovingState() {
        return movingState;
    }
}

// 客户端代码
public class ElevatorTest {
    public static void main(String[] args) {
        Elevator elevator = new Elevator();
        
        elevator.openDoors();  // 从停止到开门
        elevator.closeDoors(); // 从开门到停止
        elevator.move();       // 从停止到移动
        elevator.stop();       // 从移动到停止
        elevator.openDoors();  // 从停止到开门
    }
}