自学教程 学编程从这里开始

状态模式

《状态模式》|设计模式系列第18篇

系列:行为型模式 · 状态模式(State Pattern)
关键词:状态切换、状态封装、行为随状态改变、消除大量if/else

一、什么是状态模式

状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

属于行为型设计模式。

简单理解:
将对象的每一种状态单独封装成独立状态类。上下文(Context)持有当前状态对象;当状态切换时,上下文把请求转发给当前状态对象执行。不同状态下同一个接口会执行不同逻辑,消除臃肿的 if/else 或者 switch 判断。
例子:订单,有 Unpaid、Paid、Shipped、Finished 等状态。不同状态下,cancel、pay、ship 行为规则不一样。

核心意图
把各个状态对应的行为封装为独立类;状态变化自动切换行为,避免大量条件分支。

适用场景

  1. 对象行为依赖自身状态,并且运行时状态会发生变化
  2. 业务逻辑充斥大量 if/else 或者 switch,按状态分支
  3. 状态和对应的动作经常需要扩展
  4. 状态机、订单流转、工作流、游戏角色状态

⚠️ 缺点预警:状态数量多时,会生成大量状态类;状态切换逻辑分散在各个状态类,整体阅读难度上升。

二、UML结构图

角色划分:

  1. Context(上下文):持有当前State引用,对外暴露业务方法,转发请求给状态对象
  2. State(抽象状态):定义所有状态共用的行为接口
  3. ConcreteState(具体状态):实现State接口,处理对应状态逻辑,可触发上下文状态切换
  4. Client(客户端):创建Context,发起调用

三、Java 完整示例

场景:Order 订单流转,状态:Unpaid,Paid,Shipped。
支持操作:pay、ship。代码全部使用英文。

1. State 抽象状态

public abstract class OrderState {
    protected OrderContext context;

    public void setContext(OrderContext context) {
        this.context = context;
    }

    public abstract void pay();
    public abstract void ship();
}

2. ConcreteState 具体状态

public class UnpaidState extends OrderState {
    @Override
    public void pay() {
        System.out.println("Order paid successfully");
        context.setState(new PaidState());
    }

    @Override
    public void ship() {
        System.out.println("Cannot ship, order is unpaid");
    }
}

public class PaidState extends OrderState {
    @Override
    public void pay() {
        System.out.println("Order already paid");
    }

    @Override
    public void ship() {
        System.out.println("Order shipped successfully");
        context.setState(new ShippedState());
    }
}

public class ShippedState extends OrderState {
    @Override
    public void pay() {
        System.out.println("Cannot pay, order already shipped");
    }

    @Override
    public void ship() {
        System.out.println("Order already shipped");
    }
}

3. Context 上下文

public class OrderContext {
    private OrderState state;

    public OrderContext() {
        this.state = new UnpaidState();
        state.setContext(this);
    }

    public void setState(OrderState state) {
        this.state = state;
        state.setContext(this);
    }

    public void pay() {
        state.pay();
    }

    public void ship() {
        state.ship();
    }
}

4. Client 客户端

public class Client {
    public static void main(String[] args) {
        OrderContext order = new OrderContext();
        order.pay();
        order.ship();
        order.pay();
        order.ship();
    }
}

运行输出:

Order paid successfully
Order shipped successfully
Cannot pay, order already shipped
Order already shipped

四、状态模式 vs 策略模式

模式目标核心
State对象内部状态变化,自动切换行为;状态之间可以互相转换状态是对象内部属性,状态类知道其他状态
Strategy客户端主动替换算法;算法之间独立,互不感知算法是可选方案,由客户端选择替换

五、优缺点总结

✅ 优点

  1. 消除大量 if/else 条件分支,代码按状态拆分
  2. 新增状态只需要新增状态类,符合开闭原则
  3. 状态逻辑内聚在各自状态类,单一职责
  4. 状态流转清晰,适合状态机业务

❌ 缺点

  1. 状态种类多的时候,类数量快速膨胀
  2. 状态切换逻辑分散在各个状态类,不方便全局查看完整流转图
  3. 理解门槛高于简单if分支

六、框架源码应用

  • Spring StateMachine 状态机
  • JDK java.util.Scanner 状态处理
  • Activiti / Flowable 工作流状态

七、小结

状态模式核心:把每个状态封装为独立类,上下文持有当前状态,请求转发给状态对象执行;状态变更自动改变对象行为。
优先选择场景:订单、审批、工作流等状态驱动业务,if/else分支随状态持续增多。

标签:

0 条笔记