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

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

    • [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. 状态转换清晰:状态转换逻辑集中在状态类中

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

使用状态模式的关键点

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

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

相关推荐
__万波__2 小时前
二十三种设计模式(十八)--中介者模式
java·设计模式·中介者模式
自由生长20249 小时前
设计模式和设计原则-中高级架构思路-面向接口编程
设计模式
hdsoft_huge1 天前
Java 实现高效查询海量 geometry 及 Protobuf 序列化与天地图前端分片加载
java·前端·状态模式
大厂技术总监下海1 天前
为何顶尖科技公司都依赖它?解码 Protocol Buffers 背后的高性能、可演进设计模式
分布式·设计模式
巾帼前端1 天前
前端对用户因果链的优化
前端·状态模式
EnzoRay1 天前
代理模式
设计模式
weixin_478433321 天前
iluwatar 设计模式
java·开发语言·设计模式
郝学胜-神的一滴1 天前
Python面向对象编程:解耦、多态与魔法艺术
java·开发语言·c++·python·设计模式·软件工程
__万波__1 天前
二十三种设计模式(十六)--迭代器模式
java·设计模式·迭代器模式