状态模式(State Pattern)详解

概念与定义

状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变它的行为,使对象看起来像是修改了它的类。状态模式将状态封装成独立的类,并将动作委托到代表当前状态的对象。

核心思想

状态模式的核心是将状态与行为绑定,每个状态对应一个类,这些类实现相同的接口或继承相同的抽象类。这样,当对象的内部状态发生变化时,可以简单地切换到不同的状态类实例,从而改变对象的行为表现。

关键特点

  1. 状态对象化:将每个状态封装为一个独立的对象
  2. 行为委托:上下文对象将状态相关行为委托给当前状态对象
  3. 状态转换:状态对象可以负责状态之间的转换逻辑

典型结构

状态模式通常包含以下主要角色:

  1. Context(上下文):维护一个具体状态对象的实例,定义客户端需要的接口
  2. State(抽象状态):定义一个接口以封装与Context的特定状态相关的行为
  3. ConcreteState(具体状态):实现与Context的某个状态相关的行为

应用场景

状态模式特别适用于以下情形:

  • 对象的行为取决于它的状态,并且必须在运行时根据状态改变行为
  • 操作中包含大量的条件语句,这些条件语句依赖于对象的状态
  • 状态转换逻辑复杂,或者状态数量较多的情况

实际示例

例如在一个订单处理系统中:

  • 订单可能有"待支付"、"已支付"、"已发货"、"已完成"等不同状态
  • 每个状态下的取消操作、修改操作等行为都不同
  • 使用状态模式可以将每个状态及其行为封装为单独的类

优势

  1. 单一职责原则:将与特定状态相关的代码放在单独的类中
  2. 开闭原则:可以方便地引入新的状态而不需要修改现有状态类
  3. 消除条件语句:避免了大型的条件状态选择语句
  4. 状态转换显式化:使状态转换更加明确和可管理

核心组成部分

  1. Context(环境类)

    • 定义客户端感兴趣的接口
    • 维护一个ConcreteState子类的实例,这个实例定义当前状态
    • 示例:订单系统、电梯控制系统等
  2. State(抽象状态类)

    • 定义一个接口以封装与Context的一个特定状态相关的行为
    • 示例:OrderState接口定义订单在不同状态下的行为
  3. ConcreteState(具体状态类)

    • 每一个子类实现一个与Context的一个状态相关的行为
    • 示例:NewOrderStatePaidOrderStateShippedOrderState

实现示例

// 状态接口
public interface OrderState {
    void handlePayment(OrderContext context);
    void handleShipping(OrderContext context);
    void handleCancel(OrderContext context);
}

// 具体状态类:新订单状态
public class NewOrderState implements OrderState {
    @Override
    public void handlePayment(OrderContext context) {
        System.out.println("处理付款,订单状态变更为已付款");
        context.setState(new PaidOrderState());
    }
    
    @Override
    public void handleShipping(OrderContext context) {
        System.out.println("错误:新订单不能直接发货");
    }
    
    @Override
    public void handleCancel(OrderContext context) {
        System.out.println("订单已取消");
        context.setState(new CancelledOrderState());
    }
}

// 上下文类
public class OrderContext {
    private OrderState currentState;
    
    public OrderContext() {
        this.currentState = new NewOrderState();
    }
    
    public void setState(OrderState state) {
        this.currentState = state;
    }
    
    public void processPayment() {
        currentState.handlePayment(this);
    }
    
    public void processShipping() {
        currentState.handleShipping(this);
    }
    
    public void cancelOrder() {
        currentState.handleCancel(this);
    }
}

应用场景

  1. 订单处理系统

    • 订单从"新建"到"已付款"、"已发货"、"已完成"或"已取消"的状态转换
  2. 游戏开发

    • 游戏角色在不同状态下的行为(站立、行走、奔跑、跳跃等)
  3. 工作流引擎

    • 文档审批流程中的状态转换(草稿、待审批、已批准、已拒绝等)
  4. UI组件

    • 按钮在不同状态下的显示和行为(正常、悬停、按下、禁用等)

优缺点分析

优点:

  • 将特定状态相关的行为局部化,并且将不同状态的行为分割开来
  • 使得状态转换显式化
  • State对象可被共享(如果它们没有内部状态)

缺点:

  • 导致系统中类的数量增加
  • 当状态转换规则复杂时,Context类可能变得难以维护
  • 对"开闭原则"的支持并不完美,新增状态类需要修改负责状态转换的代码

实际应用案例:电商平台订单系统状态管理

  1. 订单状态转换流程详解:

    • New(新建):用户提交订单后的初始状态
    • Paid(已支付):用户完成支付后的状态
    • Processing(处理中):商家开始备货和打包
    • Shipped(已发货):商品出库并交由物流运输
    • Delivered(已送达):客户签收确认
    • Cancelled(已取消):订单在任何状态都可能被取消
  2. 状态相关行为详细说明:

    • 新订单行为:

      • 支付操作:调用支付接口
      • 取消操作:直接关闭订单
      • 示例:用户提交订单后30分钟内未支付自动取消
    • 已付款订单行为:

      • 退货:生成退货申请单
      • 发货:打印物流面单
      • 示例:支付后24小时内未发货需补偿优惠券
    • 已发货订单行为:

      • 确认收货:触发结算流程
      • 物流跟踪:提供实时物流信息
      • 示例:发货后7天自动确认收货
    • 已完成订单行为:

      • 评价:开放评价入口
      • 售后:开启售后服务通道
      • 示例:确认收货后15天内可申请售后
  3. 状态转换条件检查实现细节:

    • 发货前检查:

      • 支付状态校验
      • 库存占用确认
      • 地址有效性验证
      • 示例代码:
        if(!order.isPaid()){
            throw new IllegalStateException("未支付订单不能发货");
        }
        

    • 取消订单检查:

      • 发货状态判断
      • 退款流程触发
      • 库存释放处理
      • 示例场景:已发货订单需先拦截物流才能取消
  4. 状态模式优势体现:

    • 将业务规则分散到各状态类中:
      • OrderState接口定义公共方法
      • PaidState实现已支付状态特有逻辑
      • ShippedState处理物流相关操作
    • 避免庞大if-else判断:
      // 传统方式
      if(state == NEW){
          // 处理新建逻辑
      }else if(state == PAID){
          // 处理支付逻辑
      }
      //...
      
      // 状态模式
      currentState.handleRequest();
      

    • 扩展性:新增状态只需添加新类,不影响现有代码
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐