设计模式:状态模式详解-让对象的行为随状态改变而改变

设计模式:状态模式详解-让对象的行为随状态改变而改变

    • [1. 什么是状态模式?](#1. 什么是状态模式?)
    • [2. 从一个实际问题开始](#2. 从一个实际问题开始)
    • [3. 状态模式的结构](#3. 状态模式的结构)
    • [4. 状态模式的Java实现](#4. 状态模式的Java实现)
    • [5. 状态模式的优势](#5. 状态模式的优势)
      • [5.1 对比原始实现](#5.1 对比原始实现)
      • [5.2 核心优势](#5.2 核心优势)
    • [6. 状态模式的实际应用场景](#6. 状态模式的实际应用场景)
    • [7. 状态模式的变体](#7. 状态模式的变体)
      • [7.1 共享状态对象](#7.1 共享状态对象)
      • [7.2 状态转换表](#7.2 状态转换表)
      • [7.3 状态模式与策略模式的比较](#7.3 状态模式与策略模式的比较)
    • [8. Spring框架中的状态模式](#8. Spring框架中的状态模式)
      • [8.1 Spring状态机(State Machine)](#8.1 Spring状态机(State Machine))
      • [8.2 线程状态管理](#8.2 线程状态管理)
    • [9. 状态模式的最佳实践](#9. 状态模式的最佳实践)
      • [9.1 何时使用状态模式](#9.1 何时使用状态模式)
      • [9.2 实现建议](#9.2 实现建议)
      • [9.3 状态对象的创建](#9.3 状态对象的创建)
    • [10. 状态模式的局限性](#10. 状态模式的局限性)
    • [11. 总结](#11. 总结)

在软件开发中,我们经常会遇到这样的对象:它的行为取决于自身的状态,并且需要在不同状态下表现出不同的行为。如果使用大量的 if-elseswitch-case语句来判断状态,代码会变得难以维护和扩展。状态模式提供了一种优雅的解决方案。

1. 什么是状态模式?

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

简单来说,状态模式的核心思想是:

  • 将状态抽象化:将每个状态封装成独立的类
  • 将行为状态化:将与状态相关的行为分散到各个状态类中
  • 消除条件判断:用多态代替大量的条件判断语句

2. 从一个实际问题开始

假设我们要实现一个电梯系统,电梯有四种状态:开门、关门、运行、停止。电梯在不同状态下的行为不同:

  • 开门状态:不能开门(已经在开门),可以关门
  • 关门状态:可以开门,可以运行
  • 运行状态:不能开门,不能关门,可以停止
  • 停止状态:可以开门

如果不使用设计模式,我们可能会写出这样的代码:

java 复制代码
// 反面教材:使用大量的if-else判断
public class Elevator {
    private static final int OPEN = 1;
    private static final int CLOSE = 2;
    private static final int RUN = 3;
    private static final int STOP = 4;
    
    private int state;
    
    public Elevator() {
        this.state = STOP; // 初始状态为停止
    }
    
    public void open() {
        if (state == OPEN) {
            System.out.println("电梯门已经是打开状态");
        } else if (state == CLOSE) {
            System.out.println("电梯门打开");
            state = OPEN;
        } else if (state == RUN) {
            System.out.println("运行状态不能开门");
        } else if (state == STOP) {
            System.out.println("电梯门打开");
            state = OPEN;
        }
    }
    
    public void close() {
        if (state == OPEN) {
            System.out.println("电梯门关闭");
            state = CLOSE;
        } else if (state == CLOSE) {
            System.out.println("电梯门已经是关闭状态");
        } else if (state == RUN) {
            System.out.println("运行状态不能关门");
        } else if (state == STOP) {
            System.out.println("电梯已经是停止状态");
        }
    }
    
    public void run() {
        if (state == OPEN) {
            System.out.println("开门状态不能运行");
        } else if (state == CLOSE) {
            System.out.println("电梯开始运行");
            state = RUN;
        } else if (state == RUN) {
            System.out.println("电梯已经在运行");
        } else if (state == STOP) {
            System.out.println("电梯开始运行");
            state = RUN;
        }
    }
    
    public void stop() {
        if (state == OPEN) {
            System.out.println("开门状态不能停止");
        } else if (state == CLOSE) {
            System.out.println("电梯停止");
            state = STOP;
        } else if (state == RUN) {
            System.out.println("电梯停止");
            state = STOP;
        } else if (state == STOP) {
            System.out.println("电梯已经是停止状态");
        }
    }
}

这段代码的问题:

  1. 违反开闭原则:新增状态需要修改所有方法
  2. 代码臃肿:每个方法都有复杂的条件判断
  3. 难以维护:状态转换逻辑分散在各个方法中
  4. 职责不清晰:一个类负责所有状态的行为

3. 状态模式的结构

状态模式包含三个核心角色:
拥有
实现
实现
使用
使用
Context
-state: State
+request() : void
+setState(state: State) : void
<<interface>>
State
+handle(context: Context) : void
ConcreteStateA
+handle(context: Context) : void
ConcreteStateB
+handle(context: Context) : void

  • 上下文:维护一个具体状态对象的实例,定义客户感兴趣的接口
  • 抽象状态:定义一个接口,用以封装与上下文的一个特定状态相关的行为
  • 具体状态:实现抽象状态接口,定义该状态下的行为

4. 状态模式的Java实现

让我们用状态模式重构电梯系统:

步骤1:定义状态接口

java 复制代码
/**
 * 电梯状态接口
 * 定义电梯在不同状态下的行为
 */
public interface ElevatorState {
    /**
     * 开门
     */
    void open();
    
    /**
     * 关门
     */
    void close();
    
    /**
     * 运行
     */
    void run();
    
    /**
     * 停止
     */
    void stop();
}

步骤2:实现具体状态类

java 复制代码
/**
 * 开门状态
 */
public class OpenState implements ElevatorState {
    private Elevator elevator;
    
    public OpenState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void open() {
        System.out.println("电梯门已经是打开状态");
    }
    
    @Override
    public void close() {
        System.out.println("电梯门关闭");
        elevator.setState(elevator.getCloseState());
    }
    
    @Override
    public void run() {
        System.out.println("开门状态不能运行");
    }
    
    @Override
    public void stop() {
        System.out.println("开门状态不能停止");
    }
}

/**
 * 关门状态
 */
public class CloseState implements ElevatorState {
    private Elevator elevator;
    
    public CloseState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void open() {
        System.out.println("电梯门打开");
        elevator.setState(elevator.getOpenState());
    }
    
    @Override
    public void close() {
        System.out.println("电梯门已经是关闭状态");
    }
    
    @Override
    public void run() {
        System.out.println("电梯开始运行");
        elevator.setState(elevator.getRunState());
    }
    
    @Override
    public void stop() {
        System.out.println("电梯停止");
        elevator.setState(elevator.getStopState());
    }
}

/**
 * 运行状态
 */
public class RunState implements ElevatorState {
    private Elevator elevator;
    
    public RunState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void open() {
        System.out.println("运行状态不能开门");
    }
    
    @Override
    public void close() {
        System.out.println("运行状态不能关门");
    }
    
    @Override
    public void run() {
        System.out.println("电梯已经在运行");
    }
    
    @Override
    public void stop() {
        System.out.println("电梯停止");
        elevator.setState(elevator.getStopState());
    }
}

/**
 * 停止状态
 */
public class StopState implements ElevatorState {
    private Elevator elevator;
    
    public StopState(Elevator elevator) {
        this.elevator = elevator;
    }
    
    @Override
    public void open() {
        System.out.println("电梯门打开");
        elevator.setState(elevator.getOpenState());
    }
    
    @Override
    public void close() {
        System.out.println("电梯已经是停止状态");
    }
    
    @Override
    public void run() {
        System.out.println("电梯开始运行");
        elevator.setState(elevator.getRunState());
    }
    
    @Override
    public void stop() {
        System.out.println("电梯已经是停止状态");
    }
}

步骤3:创建上下文类

java 复制代码
/**
 * 电梯上下文类
 * 维护当前状态,并将请求委托给当前状态对象
 */
public class Elevator {
    // 定义所有状态
    private ElevatorState openState;
    private ElevatorState closeState;
    private ElevatorState runState;
    private ElevatorState stopState;
    
    // 当前状态
    private ElevatorState currentState;
    
    public Elevator() {
        // 初始化所有状态
        openState = new OpenState(this);
        closeState = new CloseState(this);
        runState = new RunState(this);
        stopState = new StopState(this);
        
        // 设置初始状态
        currentState = stopState;
    }
    
    // 状态操作方法 - 委托给当前状态
    public void open() {
        currentState.open();
    }
    
    public void close() {
        currentState.close();
    }
    
    public void run() {
        currentState.run();
    }
    
    public void stop() {
        currentState.stop();
    }
    
    // 状态设置方法
    public void setState(ElevatorState state) {
        this.currentState = state;
    }
    
    // 获取各个状态的方法
    public ElevatorState getOpenState() {
        return openState;
    }
    
    public ElevatorState getCloseState() {
        return closeState;
    }
    
    public ElevatorState getRunState() {
        return runState;
    }
    
    public ElevatorState getStopState() {
        return stopState;
    }
    
    // 获取当前状态
    public String getCurrentStateName() {
        if (currentState == openState) {
            return "开门状态";
        } else if (currentState == closeState) {
            return "关门状态";
        } else if (currentState == runState) {
            return "运行状态";
        } else {
            return "停止状态";
        }
    }
}

步骤4:客户端使用

java 复制代码
public class Client {
    public static void main(String[] args) {
        System.out.println("=== 电梯状态演示 ===\n");
        
        // 创建电梯
        Elevator elevator = new Elevator();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        // 测试状态转换
        System.out.println("\n1. 尝试开门");
        elevator.open();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n2. 尝试关门");
        elevator.close();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n3. 尝试运行");
        elevator.run();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n4. 运行中尝试开门");
        elevator.open();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n5. 停止电梯");
        elevator.stop();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n6. 尝试在停止状态关门");
        elevator.close();
        System.out.println("当前状态:" + elevator.getCurrentStateName());
        
        // 演示完整流程
        System.out.println("\n=== 完整使用流程 ===");
        elevator = new Elevator();
        System.out.println("初始状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n乘客进入电梯:");
        elevator.open();
        System.out.println("状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n电梯关门:");
        elevator.close();
        System.out.println("状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n电梯运行:");
        elevator.run();
        System.out.println("状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n到达目标楼层:");
        elevator.stop();
        System.out.println("状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n乘客离开电梯:");
        elevator.open();
        System.out.println("状态:" + elevator.getCurrentStateName());
        
        System.out.println("\n电梯关门待机:");
        elevator.close();
        System.out.println("状态:" + elevator.getCurrentStateName());
    }
}

输出结果:

复制代码
=== 电梯状态演示 ===

当前状态:停止状态

1. 尝试开门
电梯门打开
当前状态:开门状态

2. 尝试关门
电梯门关闭
当前状态:关门状态

3. 尝试运行
电梯开始运行
当前状态:运行状态

4. 运行中尝试开门
运行状态不能开门
当前状态:运行状态

5. 停止电梯
电梯停止
当前状态:停止状态

6. 尝试在停止状态关门
电梯已经是停止状态
当前状态:停止状态

=== 完整使用流程 ===
初始状态:停止状态

乘客进入电梯:
电梯门打开
状态:开门状态

电梯关门:
电梯门关闭
状态:关门状态

电梯运行:
电梯开始运行
状态:运行状态

到达目标楼层:
电梯停止
状态:停止状态

乘客离开电梯:
电梯门打开
状态:开门状态

电梯关门待机:
电梯门关闭
状态:关门状态

5. 状态模式的优势

5.1 对比原始实现

对比维度 原始实现(if-else) 状态模式
新增状态 需要修改所有方法 只需新增一个状态类
状态转换逻辑 分散在各个方法中 集中在状态类中
代码结构 一个方法包含所有逻辑 逻辑分散到各个状态类
可测试性 难以单独测试每种状态 每个状态类可独立测试
遵循原则 违反开闭原则、单一职责 符合开闭原则、单一职责

5.2 核心优势

  1. 消除条件判断:用多态代替复杂的条件判断语句
  2. 符合单一职责原则:每个状态类只负责自己的行为
  3. 符合开闭原则:新增状态无需修改现有代码
  4. 提高可维护性:状态转换逻辑局部化,易于理解和修改
  5. 状态转换明确:状态转换逻辑集中在状态类中,清晰可见

6. 状态模式的实际应用场景

场景1:订单状态管理

java 复制代码
/**
 * 订单状态接口
 */
public interface OrderState {
    /**
     * 支付
     */
    void pay(OrderContext context);
    
    /**
     * 发货
     */
    void ship(OrderContext context);
    
    /**
     * 确认收货
     */
    void receive(OrderContext context);
    
    /**
     * 取消订单
     */
    void cancel(OrderContext context);
    
    /**
     * 申请退款
     */
    void refund(OrderContext context);
}

/**
 * 订单上下文
 */
public class OrderContext {
    private OrderState currentState;
    private String orderId;
    
    // 各个状态实例
    private OrderState pendingState;
    private OrderState paidState;
    private OrderState shippedState;
    private OrderState receivedState;
    private OrderState cancelledState;
    private OrderState refundedState;
    
    public OrderContext(String orderId) {
        this.orderId = orderId;
        
        // 初始化所有状态
        pendingState = new PendingState(this);
        paidState = new PaidState(this);
        shippedState = new ShippedState(this);
        receivedState = new ReceivedState(this);
        cancelledState = new CancelledState(this);
        refundedState = new RefundedState(this);
        
        // 初始状态:待支付
        currentState = pendingState;
    }
    
    // 委托方法
    public void pay() {
        currentState.pay(this);
    }
    
    public void ship() {
        currentState.ship(this);
    }
    
    public void receive() {
        currentState.receive(this);
    }
    
    public void cancel() {
        currentState.cancel(this);
    }
    
    public void refund() {
        currentState.refund(this);
    }
    
    // 设置状态
    public void setState(OrderState state) {
        this.currentState = state;
        System.out.println("订单状态变更为:" + state.getClass().getSimpleName());
    }
    
    // Getter方法
    public OrderState getPendingState() { return pendingState; }
    public OrderState getPaidState() { return paidState; }
    public OrderState getShippedState() { return shippedState; }
    public OrderState getReceivedState() { return receivedState; }
    public OrderState getCancelledState() { return cancelledState; }
    public OrderState getRefundedState() { return refundedState; }
    public String getOrderId() { return orderId; }
}

/**
 * 待支付状态
 */
public class PendingState implements OrderState {
    private OrderContext context;
    
    public PendingState(OrderContext context) {
        this.context = context;
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单支付成功");
        context.setState(context.getPaidState());
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单未支付,不能发货");
    }
    
    @Override
    public void receive(OrderContext context) {
        System.out.println("订单未支付,不能确认收货");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消");
        context.setState(context.getCancelledState());
    }
    
    @Override
    public void refund(OrderContext context) {
        System.out.println("订单未支付,不能退款");
    }
}

/**
 * 已支付状态
 */
public class PaidState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已支付,无需重复支付");
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单发货成功");
        context.setState(context.getShippedState());
    }
    
    @Override
    public void receive(OrderContext context) {
        System.out.println("订单尚未发货,不能确认收货");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消,发起退款");
        context.setState(context.getRefundedState());
    }
    
    @Override
    public void refund(OrderContext context) {
        System.out.println("订单退款成功");
        context.setState(context.getRefundedState());
    }
}

场景2:TCP连接状态

java 复制代码
/**
 * TCP连接状态
 */
public interface TCPState {
    void open(TCPConnection connection);
    void close(TCPConnection connection);
    void acknowledge(TCPConnection connection);
}

/**
 * TCP连接
 */
public class TCPConnection {
    private TCPState state;
    
    // 各个状态
    private TCPState closedState;
    private TCPState listenState;
    private TCPState establishedState;
    
    public TCPConnection() {
        closedState = new TCPClosedState();
        listenState = new TCPListenState();
        establishedState = new TCPEstablishedState();
        
        state = closedState; // 初始状态:关闭
    }
    
    public void setState(TCPState state) {
        this.state = state;
    }
    
    public void open() {
        state.open(this);
    }
    
    public void close() {
        state.close(this);
    }
    
    public void acknowledge() {
        state.acknowledge(this);
    }
    
    // Getter方法
    public TCPState getClosedState() { return closedState; }
    public TCPState getListenState() { return listenState; }
    public TCPState getEstablishedState() { return establishedState; }
}

/**
 * TCP关闭状态
 */
public class TCPClosedState implements TCPState {
    @Override
    public void open(TCPConnection connection) {
        System.out.println("打开连接");
        connection.setState(connection.getListenState());
    }
    
    @Override
    public void close(TCPConnection connection) {
        System.out.println("连接已经是关闭状态");
    }
    
    @Override
    public void acknowledge(TCPConnection connection) {
        System.out.println("连接关闭,无法确认");
    }
}

/**
 * TCP监听状态
 */
public class TCPListenState implements TCPState {
    @Override
    public void open(TCPConnection connection) {
        System.out.println("连接已经是打开状态");
    }
    
    @Override
    public void close(TCPConnection connection) {
        System.out.println("关闭连接");
        connection.setState(connection.getClosedState());
    }
    
    @Override
    public void acknowledge(TCPConnection connection) {
        System.out.println("确认连接");
        connection.setState(connection.getEstablishedState());
    }
}

7. 状态模式的变体

7.1 共享状态对象

在某些情况下,多个上下文可以共享同一个状态对象。这时状态对象不应该持有上下文的引用。

java 复制代码
/**
 * 可共享的状态对象
 */
public class SharedState implements State {
    // 不持有上下文引用
    @Override
    public void handle() {
        System.out.println("处理共享状态");
        // 不能直接操作上下文,需要其他方式传递上下文信息
    }
}

/**
 * 上下文类
 */
public class SharedContext {
    private State state;
    
    public void request() {
        state.handle();
        // 根据处理结果决定状态转换
        if (shouldChangeState()) {
            state = nextState();
        }
    }
    
    private boolean shouldChangeState() {
        // 判断是否需要转换状态
        return true;
    }
    
    private State nextState() {
        // 返回下一个状态
        return new AnotherState();
    }
}

7.2 状态转换表

对于复杂的状态转换,可以使用状态转换表来管理。

java 复制代码
/**
 * 使用状态转换表
 */
public class StateMachine {
    // 状态转换表:Map<当前状态, Map<事件, 下一状态>>
    private Map<State, Map<Event, State>> transitionTable = new HashMap<>();
    private State currentState;
    
    public StateMachine(State initialState) {
        this.currentState = initialState;
        initTransitionTable();
    }
    
    private void initTransitionTable() {
        // 初始化状态转换表
        Map<Event, State> fromStateA = new HashMap<>();
        fromStateA.put(Event.EVENT_1, State.STATE_B);
        fromStateA.put(Event.EVENT_2, State.STATE_C);
        transitionTable.put(State.STATE_A, fromStateA);
        
        Map<Event, State> fromStateB = new HashMap<>();
        fromStateB.put(Event.EVENT_3, State.STATE_C);
        transitionTable.put(State.STATE_B, fromStateB);
        
        // 更多状态转换...
    }
    
    public void handleEvent(Event event) {
        Map<Event, State> transitions = transitionTable.get(currentState);
        if (transitions != null && transitions.containsKey(event)) {
            State nextState = transitions.get(event);
            System.out.println("状态转换:" + currentState + " -> " + nextState);
            currentState = nextState;
        } else {
            System.out.println("无效的事件:" + event + ",当前状态:" + currentState);
        }
    }
}

enum State {
    STATE_A, STATE_B, STATE_C
}

enum Event {
    EVENT_1, EVENT_2, EVENT_3
}

7.3 状态模式与策略模式的比较

状态模式和策略模式在结构上很相似,但它们的意图不同:

对比维度 状态模式 策略模式
意图 对象的行为随状态改变 封装可互换的算法
状态转换 状态对象知道下一个状态 客户端选择策略
状态数量 通常状态数量有限 策略数量可能很多
状态知晓 状态知道上下文 策略通常不知道上下文
示例 订单状态、电梯状态 排序算法、支付方式

8. Spring框架中的状态模式

Spring框架虽然没有直接使用经典的状态模式,但其状态管理思想无处不在:

8.1 Spring状态机(State Machine)

java 复制代码
// Spring Statemachine 示例
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
    
    @Override
    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
        states
            .withStates()
                .initial("CREATED")  // 初始状态
                .state("PAID")       // 已支付
                .state("SHIPPED")    // 已发货
                .state("DELIVERED")  // 已送达
                .state("CANCELLED"); // 已取消
    }
    
    @Override
    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
        transitions
            .withExternal()
                .source("CREATED").target("PAID").event("PAY")
            .and()
            .withExternal()
                .source("PAID").target("SHIPPED").event("SHIP")
            .and()
            .withExternal()
                .source("SHIPPED").target("DELIVERED").event("DELIVER")
            .and()
            .withExternal()
                .source("CREATED").target("CANCELLED").event("CANCEL")
            .and()
            .withExternal()
                .source("PAID").target("CANCELLED").event("CANCEL");
    }
}

// 使用状态机
@Service
public class OrderService {
    
    @Autowired
    private StateMachine<String, String> stateMachine;
    
    public void payOrder(String orderId) {
        // 发送支付事件
        stateMachine.sendEvent("PAY");
        
        // 获取当前状态
        String currentState = stateMachine.getState().getId();
        System.out.println("订单状态:" + currentState);
    }
}

8.2 线程状态管理

java 复制代码
/**
 * 模拟线程状态管理
 */
public class ThreadStateManager {
    
    public enum ThreadState {
        NEW,          // 新建
        RUNNABLE,     // 可运行
        RUNNING,      // 运行中
        BLOCKED,      // 阻塞
        WAITING,      // 等待
        TERMINATED    // 终止
    }
    
    private ThreadState currentState = ThreadState.NEW;
    
    public synchronized void start() {
        if (currentState == ThreadState.NEW) {
            currentState = ThreadState.RUNNABLE;
            System.out.println("线程进入可运行状态");
        } else {
            throw new IllegalThreadStateException("线程不能从" + currentState + "状态开始");
        }
    }
    
    public synchronized void run() {
        if (currentState == ThreadState.RUNNABLE) {
            currentState = ThreadState.RUNNING;
            System.out.println("线程开始运行");
        } else {
            throw new IllegalThreadStateException("线程不能从" + currentState + "状态运行");
        }
    }
    
    public synchronized void block() {
        if (currentState == ThreadState.RUNNING) {
            currentState = ThreadState.BLOCKED;
            System.out.println("线程被阻塞");
        }
    }
    
    public synchronized void terminate() {
        if (currentState != ThreadState.TERMINATED) {
            currentState = ThreadState.TERMINATED;
            System.out.println("线程终止");
        }
    }
    
    public ThreadState getCurrentState() {
        return currentState;
    }
}

9. 状态模式的最佳实践

9.1 何时使用状态模式

场景 是否适合状态模式 说明
对象的行为取决于状态 ✅ 非常适合 如订单、电梯、线程等
有大量的状态判断 ✅ 非常适合 用多态代替if-else
状态转换复杂 ✅ 非常适合 状态转换逻辑局部化
状态数量很少 ❌ 可能过度设计 简单的if-else更直接
状态不频繁变化 ❌ 可能过度设计 考虑其他模式

9.2 实现建议

  1. 将状态定义为不可变对象:状态对象通常是无状态的,可以被多个上下文共享
  2. 使用枚举简化状态管理:对于有限的状态,可以使用枚举
  3. 考虑使用状态机框架:对于复杂的状态转换,考虑使用Spring Statemachine等框架
  4. 分离状态转换逻辑:将状态转换逻辑集中在状态类中
  5. 提供状态查询接口:允许客户端查询当前状态

9.3 状态对象的创建

java 复制代码
/**
 * 状态工厂 - 管理状态对象的创建
 */
public class StateFactory {
    // 使用单例模式共享状态对象
    private static final Map<String, State> states = new HashMap<>();
    
    static {
        // 初始化所有状态对象
        states.put("OPEN", new OpenState());
        states.put("CLOSE", new CloseState());
        states.put("RUN", new RunState());
        states.put("STOP", new StopState());
    }
    
    public static State getState(String stateName) {
        State state = states.get(stateName);
        if (state == null) {
            throw new IllegalArgumentException("未知状态: " + stateName);
        }
        return state;
    }
    
    // 延迟初始化
    public static State getStateLazy(String stateName) {
        return states.computeIfAbsent(stateName, name -> {
            switch (name) {
                case "OPEN": return new OpenState();
                case "CLOSE": return new CloseState();
                case "RUN": return new RunState();
                case "STOP": return new StopState();
                default: throw new IllegalArgumentException("未知状态: " + name);
            }
        });
    }
}

10. 状态模式的局限性

  1. 可能增加类的数量:每个状态一个类,可能导致类数量增加
  2. 状态转换逻辑分散:状态转换逻辑分散在各个状态类中
  3. 共享状态需要特殊处理:如果状态对象需要持有上下文引用,则不能共享
  4. 可能过度设计:对于简单的状态转换,使用if-else更直接

11. 总结

状态模式是一种强大的设计模式,它将对象的状态封装成独立的类,使得对象的行为能够随着内部状态的改变而改变。通过使用状态模式,我们可以:

  1. 消除条件判断:用多态代替复杂的if-else语句
  2. 提高代码可维护性:每个状态类职责单一,易于理解和修改
  3. 符合开闭原则:新增状态无需修改现有代码
  4. 状态转换清晰:状态转换逻辑集中在状态类中

状态模式的核心价值在于它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。这使得增加新的状态变得容易,并且减少了状态转换的条件逻辑。

使用状态模式的关键点

  • 确定对象有哪些状态
  • 确定每个状态下的行为
  • 确定状态之间的转换条件
  • 将每个状态封装成独立的类

状态模式在游戏开发、工作流引擎、订单系统等领域有着广泛的应用。

相关推荐
一条闲鱼_mytube5 小时前
智能体设计模式(五)人机协同-知识检索RAG-智能体间通信
网络·人工智能·设计模式
小码过河.5 小时前
设计模式——建造者模式
单片机·设计模式·建造者模式
小码过河.7 小时前
设计模式——工厂方法模式
设计模式·工厂方法模式
把csdn当日记本的菜鸡8 小时前
Java设计模式简单入门
java·开发语言·设计模式
老蒋每日coding8 小时前
AI Agent 设计模式系列(十一)—— 目标设定和监控模式
人工智能·设计模式·langchain
蔺太微9 小时前
外观模式(Facade Pattern)
设计模式·外观模式
进击的小头9 小时前
C语言实现设计模式的核心基石
c语言·开发语言·设计模式
前端不太难9 小时前
Flutter / RN / iOS 的状态策略,该如何取舍?
flutter·ios·状态模式
Engineer邓祥浩9 小时前
设计模式学习(15) 23-13 模版方法模式
java·学习·设计模式
茶本无香9 小时前
设计模式之四:建造者模式(Builder Pattern)详解
java·设计模式·建造者模式