Skip to content

状态模式 (State Pattern)

概述

状态模式是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为。对象看起来好像修改了它的类,因为它的行为会随着其状态的改变而改变。

状态模式的核心思想是将对象的状态封装为独立的类,每个状态类实现特定状态下的行为。当对象的状态发生变化时,它会切换到对应的状态对象,从而改变其行为方式。

核心要点

  • 状态封装:将不同状态的行为封装到单独的状态类中
  • 行为切换:通过切换状态对象来改变对象的行为
  • 状态转换:状态转换可以在状态类内部或上下文类中控制
  • 单一职责:每个状态类只负责处理一种状态下的行为
  • 消除条件语句:用多态替代复杂的条件判断语句

应用场景

  • 对象行为随状态改变:当一个对象的行为取决于其当前状态,并且需要在运行时根据状态改变行为
  • 复杂条件语句:当对象的行为包含大量与状态相关的条件判断语句
  • 状态转换明确:当对象的状态转换关系比较明确且可预测
  • 有限状态机:实现有限状态机(FSM)的场景
  • 工作流引擎:实现业务流程中的状态转换和行为控制

结构

状态模式包含以下角色:

  1. 上下文(Context):维护一个指向当前状态对象的引用,并将与状态相关的操作委托给当前状态对象
  2. 状态(State):定义所有具体状态的共同接口
  3. 具体状态(Concrete State):实现状态接口,定义特定状态下的行为,并处理状态转换

实现示例

1. 基本状态模式实现

java
// 状态接口
public interface State {
    // 处理请求的方法
    void handle(Context context);
    // 获取状态名称
    String getStateName();
}

// 上下文类
public class Context {
    private State currentState; // 当前状态
    private String name; // 上下文名称
    private int count = 0; // 状态转换计数
    
    public Context(String name) {
        this.name = name;
        // 默认初始状态为状态A
        this.currentState = new ConcreteStateA();
        System.out.println("创建上下文 '" + name + "',初始状态为: " + currentState.getStateName());
    }
    
    // 设置当前状态
    public void setState(State state) {
        if (this.currentState != state) {
            this.currentState = state;
            this.count++;
            System.out.println("上下文 '" + name + "' 状态变更为: " + state.getStateName() + 
                             ",转换计数: " + count);
        }
    }
    
    // 获取当前状态
    public State getState() {
        return currentState;
    }
    
    // 处理请求(委托给当前状态)
    public void request() {
        System.out.println("上下文 '" + name + "' 收到请求,当前状态: " + currentState.getStateName());
        currentState.handle(this);
    }
    
    // 获取上下文名称
    public String getName() {
        return name;
    }
    
    // 获取状态转换计数
    public int getCount() {
        return count;
    }
    
    @Override
    public String toString() {
        return "Context{name='" + name + "', state=" + currentState.getStateName() + ", count=" + count + "}";
    }
}

// 具体状态A
public class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("状态A 处理请求");
        // 状态转换:从A转换到B
        System.out.println("触发状态转换:A -> B");
        context.setState(new ConcreteStateB());
    }
    
    @Override
    public String getStateName() {
        return "ConcreteStateA";
    }
    
    @Override
    public String toString() {
        return getStateName();
    }
}

// 具体状态B
public class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("状态B 处理请求");
        // 状态转换:从B转换到C
        System.out.println("触发状态转换:B -> C");
        context.setState(new ConcreteStateC());
    }
    
    @Override
    public String getStateName() {
        return "ConcreteStateB";
    }
    
    @Override
    public String toString() {
        return getStateName();
    }
}

// 具体状态C
public class ConcreteStateC implements State {
    @Override
    public void handle(Context context) {
        System.out.println("状态C 处理请求");
        // 状态转换:从C转换回A,形成一个循环
        System.out.println("触发状态转换:C -> A");
        context.setState(new ConcreteStateA());
    }
    
    @Override
    public String getStateName() {
        return "ConcreteStateC";
    }
    
    @Override
    public String toString() {
        return getStateName();
    }
}

// 客户端
public class StatePatternDemo {
    public static void main(String[] args) {
        // 创建上下文
        Context context = new Context("示例上下文");
        System.out.println("\n===== 状态模式演示 =====\n");
        
        // 执行多次请求,观察状态转换
        for (int i = 1; i <= 5; i++) {
            System.out.println("\n----- 请求 #" + i + " -----");
            context.request();
            System.out.println("当前上下文状态: " + context);
        }
        
        // 创建第二个上下文进行对比
        System.out.println("\n----- 创建第二个上下文 -----");
        Context context2 = new Context("对比上下文");
        
        // 直接设置状态(外部控制状态转换)
        System.out.println("\n----- 外部控制状态转换 -----");
        context2.setState(new ConcreteStateC());
        context2.request();
        
        System.out.println("\n===== 演示结束 =====");
        System.out.println("第一个上下文最终状态: " + context);
        System.out.println("第二个上下文最终状态: " + context2);
    }
}

2. 复杂状态机实现

下面是一个更复杂的状态机实现,展示如何处理更复杂的状态转换逻辑:

java
import java.util.HashMap;
import java.util.Map;

// 事件类型枚举
enum EventType {
    EVENT_A, EVENT_B, EVENT_C, EVENT_D
}

// 状态接口
public interface State {
    // 获取状态名称
    String getStateName();
    // 处理特定事件
    State handleEvent(EventType event);
    // 进入状态时的行为
    void onEntry();
    // 退出状态时的行为
    void onExit();
}

// 上下文类(状态机)
public class StateMachine {
    private String name; // 状态机名称
    private State currentState; // 当前状态
    private Map<String, State> states = new HashMap<>(); // 所有可能的状态
    private int transitionCount = 0; // 状态转换计数
    
    public StateMachine(String name) {
        this.name = name;
        System.out.println("创建状态机: " + name);
    }
    
    // 添加状态
    public void addState(State state) {
        states.put(state.getStateName(), state);
        System.out.println("添加状态到状态机: " + state.getStateName());
    }
    
    // 设置初始状态
    public void setInitialState(String stateName) {
        if (states.containsKey(stateName)) {
            this.currentState = states.get(stateName);
            System.out.println("设置初始状态: " + stateName);
            currentState.onEntry(); // 执行进入状态行为
        } else {
            throw new IllegalArgumentException("状态不存在: " + stateName);
        }
    }
    
    // 处理事件
    public void handleEvent(EventType event) {
        System.out.println("\n状态机 '" + name + "' 处理事件: " + event + ", 当前状态: " + currentState.getStateName());
        
        // 处理事件,获取下一个状态
        State nextState = currentState.handleEvent(event);
        
        // 如果状态发生变化
        if (nextState != null && nextState != currentState) {
            // 退出当前状态
            currentState.onExit();
            
            // 转换到新状态
            this.currentState = nextState;
            this.transitionCount++;
            System.out.println("状态转换: " + nextState.getStateName() + ", 转换计数: " + transitionCount);
            
            // 进入新状态
            currentState.onEntry();
        } else if (nextState == null) {
            System.out.println("此事件在当前状态下没有定义转换");
        } else {
            System.out.println("状态未发生变化");
        }
    }
    
    // 获取当前状态
    public State getCurrentState() {
        return currentState;
    }
    
    // 获取状态转换计数
    public int getTransitionCount() {
        return transitionCount;
    }
    
    // 获取状态机名称
    public String getName() {
        return name;
    }
    
    @Override
    public String toString() {
        return "StateMachine{name='" + name + "', currentState=" + 
               (currentState != null ? currentState.getStateName() : "null") + ", transitionCount=" + 
               transitionCount + ", stateCount=" + states.size() + "}";
    }
}

// 具体状态:待机状态
public class StandbyState implements State {
    @Override
    public String getStateName() {
        return "StandbyState";
    }
    
    @Override
    public State handleEvent(EventType event) {
        switch (event) {
            case EVENT_A:
                System.out.println("待机状态下收到事件A,转换到运行状态");
                return new RunningState();
            case EVENT_B:
                System.out.println("待机状态下收到事件B,转换到暂停状态");
                return new PausedState();
            default:
                System.out.println("待机状态下忽略事件: " + event);
                return this; // 状态不变
        }
    }
    
    @Override
    public void onEntry() {
        System.out.println("进入待机状态: 系统初始化完成,等待启动命令");
    }
    
    @Override
    public void onExit() {
        System.out.println("退出待机状态: 开始执行任务");
    }
}

// 具体状态:运行状态
public class RunningState implements State {
    private int executionCount = 0;
    
    @Override
    public String getStateName() {
        return "RunningState";
    }
    
    @Override
    public State handleEvent(EventType event) {
        switch (event) {
            case EVENT_B:
                System.out.println("运行状态下收到事件B,转换到暂停状态");
                return new PausedState();
            case EVENT_C:
                System.out.println("运行状态下收到事件C,转换到完成状态");
                return new CompletedState();
            case EVENT_D:
                System.out.println("运行状态下收到事件D,转换到错误状态");
                return new ErrorState();
            default:
                System.out.println("运行状态下忽略事件: " + event);
                return this; // 状态不变
        }
    }
    
    @Override
    public void onEntry() {
        executionCount++;
        System.out.println("进入运行状态: 开始执行任务,执行次数: " + executionCount);
    }
    
    @Override
    public void onExit() {
        System.out.println("退出运行状态: 任务执行中断或完成");
    }
    
    public int getExecutionCount() {
        return executionCount;
    }
}

// 具体状态:暂停状态
public class PausedState implements State {
    private long pauseStartTime;
    
    @Override
    public String getStateName() {
        return "PausedState";
    }
    
    @Override
    public State handleEvent(EventType event) {
        switch (event) {
            case EVENT_A:
                System.out.println("暂停状态下收到事件A,恢复到运行状态");
                return new RunningState();
            case EVENT_C:
                System.out.println("暂停状态下收到事件C,转换到完成状态");
                return new CompletedState();
            default:
                System.out.println("暂停状态下忽略事件: " + event);
                return this; // 状态不变
        }
    }
    
    @Override
    public void onEntry() {
        pauseStartTime = System.currentTimeMillis();
        System.out.println("进入暂停状态: 任务执行暂停");
    }
    
    @Override
    public void onExit() {
        long pausedTime = System.currentTimeMillis() - pauseStartTime;
        System.out.println("退出暂停状态: 继续执行任务,暂停时长: " + pausedTime + "ms");
    }
}

// 具体状态:完成状态
public class CompletedState implements State {
    @Override
    public String getStateName() {
        return "CompletedState";
    }
    
    @Override
    public State handleEvent(EventType event) {
        switch (event) {
            case EVENT_A:
                System.out.println("完成状态下收到事件A,重置到待机状态");
                return new StandbyState();
            default:
                System.out.println("完成状态下忽略事件: " + event);
                return this; // 状态不变
        }
    }
    
    @Override
    public void onEntry() {
        System.out.println("进入完成状态: 任务执行成功完成");
    }
    
    @Override
    public void onExit() {
        System.out.println("退出完成状态: 准备开始新任务");
    }
}

// 具体状态:错误状态
public class ErrorState implements State {
    private String errorMessage = "未知错误";
    
    public ErrorState() {
        // 默认构造函数
    }
    
    public ErrorState(String errorMessage) {
        this.errorMessage = errorMessage;
    }
    
    @Override
    public String getStateName() {
        return "ErrorState";
    }
    
    @Override
    public State handleEvent(EventType event) {
        switch (event) {
            case EVENT_A:
                System.out.println("错误状态下收到事件A,重置到待机状态");
                return new StandbyState();
            case EVENT_D:
                System.out.println("错误状态下收到事件D,尝试恢复到运行状态");
                return new RunningState();
            default:
                System.out.println("错误状态下忽略事件: " + event);
                return this; // 状态不变
        }
    }
    
    @Override
    public void onEntry() {
        System.out.println("进入错误状态: " + errorMessage);
    }
    
    @Override
    public void onExit() {
        System.out.println("退出错误状态: 错误已处理或重置");
    }
    
    public String getErrorMessage() {
        return errorMessage;
    }
}

// 客户端:复杂状态机演示
public class ComplexStateMachineDemo {
    public static void main(String[] args) {
        // 创建状态机
        StateMachine stateMachine = new StateMachine("工作流状态机");
        
        // 添加所有可能的状态
        stateMachine.addState(new StandbyState());
        stateMachine.addState(new RunningState());
        stateMachine.addState(new PausedState());
        stateMachine.addState(new CompletedState());
        stateMachine.addState(new ErrorState());
        
        System.out.println("\n===== 复杂状态机演示 =====\n");
        
        // 设置初始状态
        stateMachine.setInitialState("StandbyState");
        
        // 模拟事件序列
        System.out.println("\n----- 正常工作流程 -----");
        stateMachine.handleEvent(EventType.EVENT_A); // 待机 -> 运行
        stateMachine.handleEvent(EventType.EVENT_B); // 运行 -> 暂停
        stateMachine.handleEvent(EventType.EVENT_A); // 暂停 -> 运行
        stateMachine.handleEvent(EventType.EVENT_C); // 运行 -> 完成
        
        System.out.println("\n----- 重置流程 -----");
        stateMachine.handleEvent(EventType.EVENT_A); // 完成 -> 待机
        
        System.out.println("\n----- 错误处理流程 -----");
        stateMachine.handleEvent(EventType.EVENT_A); // 待机 -> 运行
        stateMachine.handleEvent(EventType.EVENT_D); // 运行 -> 错误
        stateMachine.handleEvent(EventType.EVENT_A); // 错误 -> 待机
        
        System.out.println("\n----- 异常事件处理 -----");
        stateMachine.handleEvent(EventType.EVENT_D); // 待机状态下忽略此事件
        
        System.out.println("\n===== 状态机最终状态 =====");
        System.out.println(stateMachine);
    }
}

实际应用示例:订单状态管理系统

下面是一个订单状态管理系统的实际应用示例,展示如何使用状态模式实现电商系统中的订单状态管理:

java
import java.util.*;
import java.text.SimpleDateFormat;

// 订单事件枚举
enum OrderEvent {
    CREATE,
    PAY,
    SHIP,
    DELIVER,
    CANCEL,
    REFUND,
    COMPLETE
}

// 订单状态接口
public interface OrderState {
    // 获取状态名称
    String getStateName();
    // 获取状态描述
    String getDescription();
    // 处理事件
    OrderState handleEvent(OrderContext context, OrderEvent event);
    // 进入状态时的行为
    void onEntry(OrderContext context);
    // 退出状态时的行为
    void onExit(OrderContext context);
    // 获取此状态下可执行的事件列表
    List<OrderEvent> getAvailableEvents();
}

// 订单上下文类
public class OrderContext {
    private String orderId; // 订单ID
    private OrderState currentState; // 当前状态
    private BigDecimal totalAmount; // 订单总金额
    private String customerId; // 客户ID
    private Date createTime; // 创建时间
    private Date lastUpdateTime; // 最后更新时间
    private List<OrderHistory> history = new ArrayList<>(); // 订单历史
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    public OrderContext(String orderId, String customerId, BigDecimal totalAmount) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.totalAmount = totalAmount;
        this.createTime = new Date();
        this.lastUpdateTime = new Date();
        
        // 初始状态为待支付
        this.currentState = new PendingPaymentState();
        
        System.out.println("创建订单: " + orderId);
        System.out.println("  客户ID: " + customerId);
        System.out.println("  总金额: " + totalAmount);
        System.out.println("  创建时间: " + dateFormat.format(createTime));
        
        // 记录初始状态
        addHistory("订单创建", "初始状态: " + currentState.getStateName());
        currentState.onEntry(this);
    }
    
    // 处理事件
    public void handleEvent(OrderEvent event) {
        System.out.println("\n订单 '" + orderId + "' 处理事件: " + event + ", 当前状态: " + currentState.getStateName());
        
        // 检查事件是否可用
        List<OrderEvent> availableEvents = currentState.getAvailableEvents();
        if (!availableEvents.contains(event)) {
            System.out.println("错误: 当前状态 '" + currentState.getStateName() + "' 下不能执行事件 '