深入设计模式之「状态模式」:行为随状态切换而改变的优雅设计

一、什么是状态模式?

状态模式(State Pattern) 是一种行为型设计模式,允许对象在其内部状态发生改变时,改变其行为,就好像它改变了所属的类一样。

它将与状态相关的行为抽取为独立类,使状态切换更清晰、行为更灵活,避免了大量的条件分支。


二、为什么要使用状态模式?

✅ 场景痛点:条件分支混乱 & 行为难维护

面对多状态切换的场景,我们经常写出如下代码:

if (state == "草稿") { ... }
else if (state == "审核中") { ... }
else if (state == "已发布") { ... }

这类逻辑会导致:

  • 状态逻辑紧耦合在一起,难以扩展

  • 添加新状态风险极高,需遍历所有分支

  • 单一方法中塞入过多职责

状态模式的目标:将每种状态的行为独立封装,替代条件语句,使状态变化过程更具弹性与可维护性。


✅ 类比说明:电梯的行为控制

电梯状态可能有:运行中、停止中、维护中。

不同状态下:

  • 接到“上楼”指令时行为不同

  • 接到“关门”请求时行为不同

使用状态模式可将“运行状态”和其行为分开,避免硬编码条件判断。


三、状态模式的结构

角色

说明

Context

环境类,持有当前状态对象,提供行为调用接口

State

状态接口,定义所有状态共有的方法

ConcreteState

具体状态类,实现各状态下的具体行为


四、Java 实现:订单状态流转系统

✅ 1. State 接口(抽象状态)

public interface OrderState {
    void handle(OrderContext context);
}

✅ 2. Context 类(订单上下文)

public class OrderContext {
    private OrderState currentState;
    public void setState(OrderState state) {
        this.currentState = state;
    }
    public void process() {
        currentState.handle(this);
    }
}


✅ 3. 各具体状态类

草稿状态

public class DraftState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("当前状态:草稿,提交订单...");
        context.setState(new SubmittedState());
    }
}

已提交状态

public class SubmittedState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("当前状态:已提交,开始支付...");
        context.setState(new PaidState());
    }
}

已支付状态

public class PaidState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("当前状态:已支付,准备发货...");
        context.setState(new ShippedState());
    }
}

已发货状态

public class ShippedState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("当前状态:已发货,完成订单!");
    }
}


✅ 4. 测试执行流程

public class Main {
    public static void main(String[] args) {
        OrderContext order = new OrderContext();
        order.setState(new DraftState());
        order.process(); // 提交订单
        order.process(); // 支付
        order.process(); // 发货
        order.process(); // 完成
    }
}

五、应用场景总结

应用场景

描述

状态随时间或事件切换的业务流

如订单流程、审批流程、任务状态流转等

有限状态集合,且状态行为差异明显

每个状态拥有独立逻辑,如游戏人物状态(攻击、防御、死亡)

避免冗长的 if-else/switch 结构

结构灵活,便于维护和扩展


六、状态模式的优点

优点

描述

消除了 if-else/switch 条件判断

每种状态独立维护逻辑

遵循开闭原则

添加新状态无需修改原有代码

状态切换清晰,行为封装独立

各状态逻辑清晰明确

有利于状态复用与测试

每个状态类可单独测试


七、缺点及典型问题场景

缺点

场景示例

状态类数量爆炸

状态过多时会导致类数量增加

状态切换控制分散

若状态切换太分散,难以管理状态流转

引入额外抽象成本

对于状态较少的场景,反而增加复杂度


❌ 缺点场景举例与解决方案

场景 1:复杂游戏角色状态爆炸

游戏中角色有十几种状态(移动、攻击、防御、中毒、隐身、眩晕、死亡…),每个状态之间又有交叉流转,导致状态类数量激增。

✅ 解决方案:

  • 将状态分组聚合(如“生存状态组”、“技能状态组”)

  • 使用状态工厂统一创建管理状态对象


场景 2:状态切换混乱导致逻辑错误

若状态切换逻辑被多个模块调用,且没有统一封装状态转移规则,可能造成状态错误(如订单直接从“草稿”跳到“已发货”)。

✅ 解决方案:

  • 通过状态机控制器集中处理状态流转规则

  • 引入“允许切换状态集”进行状态白名单控制


八、扩展方向

扩展方向

描述

状态图可视化

使用状态图工具建模(如 PlantUML)

状态持久化

当前状态可存储到数据库,支持恢复

状态与事件解耦

结合“事件驱动”模型进行状态变更

引入状态工厂模式

统一管理状态对象实例创建


九、总结

状态模式 适用于对象需要频繁根据状态切换行为的业务场景。

适用前提

  • 状态有限且行为差异大

  • 存在状态切换逻辑

使用建议

  • 控制状态类数量,防止“类爆炸”

  • 管理状态转换流程,避免不合法状态跳转

  • 与状态图建模工具结合使用,提升协作与可维护性

下一篇将带你深入讲解「策略模式」的核心思想与进阶用法 ‍

你可能感兴趣的:(设计模式,设计模式,状态模式)