Bootstrap

设计模式详解(九):状态模式——State

状态模式详解

状态模式(State Pattern)是行为型设计模式的一种,它允许对象在内部状态发生改变时改变其行为,看起来像是改变了其类。状态模式通过将状态的行为封装到独立的状态类中,从而使得状态切换变得清晰且易于维护。


1. 什么是状态模式

状态模式主要解决的是对象在不同状态下表现出不同行为的问题。其核心思想是:

  • 状态切换:将状态转移逻辑放入状态对象中,而不是集中在一个类里。
  • 行为封装:将与特定状态相关的行为封装到独立的状态类中。

适用场景:

  1. 对象的行为依赖于其状态。
  2. 状态的数量相对有限,且可能需要频繁切换。

2. 状态模式的结构

状态模式的 UML 类图如下:

> currentState
> doAction()
> doAction()
Context
State
ConcreteStateA
ConcreteStateB

组件分析:

  1. Context(上下文)

    • 持有当前状态的引用。
    • 对客户端提供接口,并将请求委托给当前状态。
  2. State(状态接口)

    • 定义状态行为的公共接口。
  3. ConcreteState(具体状态类)

    • 实现具体状态的行为。
    • 包含可能导致状态切换的逻辑。

3. 实现代码示例

以下是一个简单的状态模式实现案例:

需求:

模拟一个电灯的开关,电灯有“开”和“关”两种状态。

实现代码

// 状态接口
public interface State {
    void handle(Context context);
}

// 具体状态类 - 开灯状态
public class OnState implements State {
    @Override
    public void handle(Context context) {
        System.out.println("灯已开启,切换到关闭状态。");
        context.setState(new OffState());
    }
}

// 具体状态类 - 关灯状态
public class OffState implements State {
    @Override
    public void handle(Context context) {
        System.out.println("灯已关闭,切换到开启状态。");
        context.setState(new OnState());
    }
}

// 上下文类
public class Context {
    private State currentState;

    public Context(State initialState) {
        this.currentState = initialState;
    }

    public void setState(State state) {
        this.currentState = state;
    }

    public void request() {
        currentState.handle(this);
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        Context context = new Context(new OffState());

        // 模拟状态切换
        context.request(); // 输出:灯已关闭,切换到开启状态。
        context.request(); // 输出:灯已开启,切换到关闭状态。
    }
}

4. 状态模式的优缺点

优点

  1. 分离状态逻辑

    • 每个状态独立成类,职责单一,易于扩展和维护。
  2. 简化上下文类

    • 状态切换的逻辑被移到了具体状态类中,上下文类更加简洁。
  3. 符合开闭原则

    • 新增状态无需修改现有代码,只需添加新的状态类。

缺点

  1. 状态类增多

    • 每个状态需要一个类,可能导致类的数量较多。
  2. 可能增加复杂性

    • 在简单场景下,使用状态模式可能显得过于复杂。

5. 状态模式的应用场景

  1. 游戏开发

    • 游戏角色的不同状态(如行走、奔跑、跳跃等)。
  2. 工作流系统

    • 不同审批阶段的状态切换。
  3. 图形界面系统

    • 按钮的不同状态(启用、禁用、悬停、点击)。

6. 图文总结

通过状态模式,上下文类可以专注于请求的分发,而无需关心具体状态的实现。以下是其优雅之处的图示:

graph TD
    A[Context] -->|request()| B[State Interface]
    B --> C[ConcreteStateA]
    B --> D[ConcreteStateB]
    C -->|switch| D
    D -->|switch| C

状态模式在设计复杂系统时,能有效地组织状态行为,增强代码的可维护性。希望这篇文章对你理解状态模式有所帮助!

;