Skip to content

状态模式

引言

在软件开发中,当对象需要根据内部状态变化改变行为时(如订单状态流转、游戏角色动作切换),传统的if-else或switch-case会导致代码臃肿维护困难。状态模式通过封装状态行为解耦状态转换,实现了对象行为的动态切换,成为复杂状态管理的优雅解决方案。

诞生背景

GoF在《设计模式》中提出状态模式,解决三大核心痛点:

  • 行为耦合:对象行为与状态强绑定,修改状态需改动所有相关方法
  • 条件爆炸:状态判断逻辑随状态数量指数级增长
  • 扩展困难:新增状态需修改所有状态转换代码

演进过程

  • GoF基础(1994):确立状态接口与上下文协作关系
  • 工作流引擎演进:BPMN等系统将状态模式扩展为可视化状态机
  • 现代应用:前端框架的状态管理库(如Redux、XState)实现状态模式的工程化

核心概念

  • 上下文(Context):持有当前状态对象,定义客户端接口
  • 抽象状态(State):声明状态特定行为的接口
  • 具体状态(ConcreteState):实现当前状态对应的行为逻辑

通用实现

Java 实现

java
// 抽象状态
interface OrderState {
    void next(OrderContext context);
    void prev(OrderContext context);
}

// 具体状态:已下单
class PlacedState implements OrderState {
    public void next(OrderContext context) {
        context.setState(new ShippedState());
    }
    public void prev(OrderContext context) {
        System.out.println("已是最初状态");
    }
}

// 具体状态:已发货
class ShippedState implements OrderState {
    public void next(OrderContext context) {
        context.setState(new DeliveredState());
    }
    public void prev(OrderContext context) {
        context.setState(new PlacedState());
    }
}

// 上下文
class OrderContext {
    private OrderState state;
  
    public OrderContext() {
        this.state = new PlacedState(); // 初始状态
    }
  
    public void setState(OrderState state) {
        this.state = state;
    }
  
    public void nextState() {
        state.next(this);
    }
  
    public void prevState() {
        state.prev(this);
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        OrderContext order = new OrderContext();
        order.nextState(); // 状态切换:已下单 → 已发货
    }
}

PHP 实现

php
// 抽象状态
interface ElevatorState {
    public function openDoors(): void;
    public function closeDoors(): void;
}

// 具体状态:停止状态
class StoppedState implements ElevatorState {
    public function openDoors(): void {
        echo "开门中...\n";
    }
    public function closeDoors(): void {
        echo "门已关闭\n";
    }
}

// 具体状态:运行状态
class RunningState implements ElevatorState {
    public function openDoors(): void {
        throw new Exception("运行中不能开门!");
    }
    public function closeDoors(): void {
        echo "门已关闭\n";
    }
}

// 上下文
class ElevatorContext {
    private ElevatorState $state;
  
    public function __construct() {
        $this->state = new StoppedState(); // 初始状态
    }
  
    public function setState(ElevatorState $state): void {
        $this->state = $state;
    }
  
    public function requestOpen(): void {
        $this->state->openDoors();
    }
  
    public function startMoving(): void {
        $this->state = new RunningState();
        echo "电梯开始运行\n";
    }
}

// 客户端
$elevator = new ElevatorContext();
$elevator->requestOpen(); // 开门成功
$elevator->startMoving();
$elevator->requestOpen(); // 抛出异常:运行中不能开门

应用场景

  • 工作流引擎:订单状态流转(待付款→已发货→已完成)
  • 游戏开发:角色状态切换(站立→奔跑→跳跃)
  • 硬件控制:设备状态管理(待机→运行→故障)
  • UI交互:组件状态变更(禁用→激活→加载中)

案例:音乐播放器状态控制

Java 实现

java
// 抽象状态
interface PlayerState {
    void play(PlayerContext context);
    void pause(PlayerContext context);
}

// 具体状态:播放状态
class PlayingState implements PlayerState {
    public void play(PlayerContext context) {
        System.out.println("已在播放中");
    }
    public void pause(PlayerContext context) {
        context.setState(new PausedState());
        System.out.println("暂停播放");
    }
}

// 具体状态:暂停状态
class PausedState implements PlayerState {
    public void play(PlayerContext context) {
        context.setState(new PlayingState());
        System.out.println("继续播放");
    }
    public void pause(PlayerContext context) {
        System.out.println("已是暂停状态");
    }
}

// 上下文
class PlayerContext {
    private PlayerState state = new PausedState();
  
    public void setState(PlayerState state) {
        this.state = state;
    }
  
    public void pressPlay() {
        state.play(this);
    }
  
    public void pressPause() {
        state.pause(this);
    }
}

// 客户端
PlayerContext player = new PlayerContext();
player.pressPlay(); // 继续播放
player.pressPause(); // 暂停播放

PHP 实现

php
// 抽象状态
interface TrafficLightState {
    public function change(TrafficLightContext $context): void;
}

// 具体状态:红灯
class RedLight implements TrafficLightState {
    public function change(TrafficLightContext $context): void {
        echo "红灯 → 绿灯\n";
        $context->setState(new GreenLight());
    }
}

// 具体状态:绿灯
class GreenLight implements TrafficLightState {
    public function change(TrafficLightContext $context): void {
        echo "绿灯 → 黄灯\n";
        $context->setState(new YellowLight());
    }
}

// 具体状态:黄灯
class YellowLight implements TrafficLightState {
    public function change(TrafficLightContext $context): void {
        echo "黄灯 → 红灯\n";
        $context->setState(new RedLight());
    }
}

// 上下文
class TrafficLightContext {
    private TrafficLightState $state;
  
    public function __construct() {
        $this->state = new RedLight();
    }
  
    public function setState(TrafficLightState $state): void {
        $this->state = $state;
    }
  
    public function changeLight(): void {
        $this->state->change($this);
    }
}

// 客户端
$trafficLight = new TrafficLightContext();
$trafficLight->changeLight(); // 红灯 → 绿灯
$trafficLight->changeLight(); // 绿灯 → 黄灯
$trafficLight->changeLight(); // 黄灯 → 红灯

优点

  • 开闭原则:新增状态无需修改现有代码
  • 消除条件语句:用多态替代复杂的条件判断
  • 职责清晰:每个状态类封装特定行为逻辑
  • 状态转换显式化:转换逻辑集中在状态类中

缺点

  • 类数量膨胀:状态过多导致类数量增加
  • 上下文依赖:状态类需了解上下文信息
  • 转换逻辑分散:状态转换逻辑分布在多个状态类中

扩展

  • 状态共享:无内部状态的状态对象可设计为享元(Flyweight)
  • 状态表驱动:使用Map存储状态转换规则(状态→事件→新状态)
  • 层次化状态:通过继承实现状态行为的复用(如基类处理通用逻辑)

模式协作

  • 与策略模式:状态模式根据状态改变行为,策略模式主动选择算法
  • 与观察者模式:状态变更时可通知观察者(如订单状态更新通知)
  • 与单例模式:无状态的状态对象可设计为单例

延伸思考

  • 分布式状态机:Saga模式实现跨服务的分布式状态管理
  • 前端状态管理:XState库将状态模式引入前端工作流
  • AI行为树:游戏AI使用分层状态机实现复杂行为逻辑

总结

状态模式是行为动态切换的架构师,通过封装状态行为与解耦状态转换,实现了对象行为的优雅变化。其核心价值在于:消除条件分支的简洁之道开闭原则的完美实践。在订单系统、游戏引擎、硬件控制等场景中,状态模式能显著提升代码可维护性和扩展性,成为状态驱动型系统的核心架构模式。