设计模式学习(十二)状态模式

目录

一、定义

1.1 什么是状态模式?

状态模式(State Pattern) 是一种 行为型 设计模式,对有状态的对象,把复杂的 "判断逻辑" 提取到不同的状态对象中,允许状态对象在其内部状态发生改变时,改变其行为。

1.2 状态模式的优缺点

状态模式的优点:

  1. 结构清晰 :状态模式将与特定状态相关的行为局部化道一个状态中,并且将不同状态的行为分割开来,满足 "但一职责原则"。
  2. 将状态转换显示化:减少对象间的相互依赖,将不同的状态引入独立的对象中会是的状态转换变得更加明确,且减少对相见的相互依赖。
  3. 状态类职责明确:有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

状态模式的缺点:

  1. 状态模式的使用必然会增加系统的类与对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
  3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。

1.3 状态模式的实现结构

状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。现在我们来分析其基本结构和实现方法。

状态模式主要包含三个角色:

  • Context(环境类):定义客户端感兴趣的接口,维护一个 State 子类的实例,这个示例定义当前状态。
  • State(抽象状态类):定义一个接口,用以封装 Context 的特定状态相关的行为。
  • ConcreteState(具体状态类):每一个子类实现一个与 Context 的一个状态相关的行为。

二、适用场景

适用场景一:算法框架固定的场景

  • 适用原因:当多个相关类需要执行相同的工作流程或算法骨架,但其中某些具体步骤的实现各不相同。这些类共享一个通用的操作序列,只是在特定环节存在差异化实现。
  • 状态模式解决的问题:消除重复的过程控制代码,确保所有子类都遵循相同的执行顺序和流程规范。避免了在每个具体类中重复编写相同的流程控制逻辑,同时也防止了因流程修改需要在多个地方同步更新的维护负担。

适用场景二:代码复用的场景

  • 适用原因:系统中存在多个类包含大量相同的行为代码,只有部分核心逻辑存在差异。这些类在整体功能上高度相似,但在关键步骤上需要个性化实现。
  • 状态模式解决的问题:通过将公共代码提升到父类中,显著减少代码重复。当公公逻辑需要修改时,只需在父类中修改一处即可影响所有子类,大大提高了代码的可维护性和一致性。

适用场景三:控制子类扩展的场景

  • 适用原因:需要确保子类在扩展时不会破坏核心算法的结构,或者需要限制子类只能重写特定的操作步骤。系统要求对扩展行为进行规范化管理。
  • 解决的问题:防止子类随意修改关键流程,确保系统的稳定性和一致性。通过模板方法定义不可更改的算法骨架,既保证了扩展的灵活性,又维护了核心流程的稳定性。

三、代码示例:订单状态管理

3.1 背景介绍

在电商系统下,订单状态管理是一个典型的状态模式应用场景。订单会经历从创建到完成的多个状态,每个状态下可执行的操作各不相同。

3.2 问题分析

如果不使用状态模式,我们可能会写出这样的代码:

java 复制代码
public class Order {
  private String state;
  
  public void handle() {
    if ("pending".equals(state)) {
      System.out.println("订单待支付,可以支付或取消");
    } else if ("paid".equals(state)) {
      System.out.println("订单已支付,可以发货");
    } else if ("shipped".equals(state)) {
      System.out.println("订单已发货,等待确认收货");
    } else if ("completed".equals(state)) {
      System.out.println("订单已取消,不能进行任何操作");
    }
  }
  
  public void pay() {
    if ("pending".equals(state)) {
      state = "paid";
      System.out.println("支付成功");
    } else {
      System.out.println("当前状态不能支付");
    }
  }
}

这种方式的缺点很明显:

  • 大量的 if-else 语句,代码臃肿;
  • 违反开闭原则,新增状态需要修改原有代码;
  • 状态转换逻辑分散在各个方法中,难以维护;

3.3 状态模式解决方案

代码 UML 如下:
CancelledState +handle(OrderContext) +cancel(OrderContext) +pay(OrderContext) +ship(OrderContext) +confirm(OrderContext) CompletedState +confirm(OrderContext) +cancel(OrderContext) +pay(OrderContext) +handle(OrderContext) +ship(OrderContext) OrderContext +confirm() +handle() +getState() +pay() +setState(OrderState) +getOrderId() +cancel() +ship() <<Interface>> OrderState +pay(OrderContext) +ship(OrderContext) +confirm(OrderContext) +handle(OrderContext) +cancel(OrderContext) PaidState +handle(OrderContext) +ship(OrderContext) +cancel(OrderContext) +confirm(OrderContext) +pay(OrderContext) PendingState +ship(OrderContext) +handle(OrderContext) +confirm(OrderContext) +cancel(OrderContext) +pay(OrderContext) ShippedState +pay(OrderContext) +ship(OrderContext) +confirm(OrderContext) +cancel(OrderContext) +handle(OrderContext) StatePatternDemo +main(String[])

1)定义状态接口
java 复制代码
/**
 * 订单状态接口
 */
public interface OrderState {
    void handle(OrderContext context);
    void pay(OrderContext context);
    void ship(OrderContext context);
    void confirm(OrderContext context);
    void cancel(OrderContext context);
}
2)实现具体状态类
java 复制代码
/**
 * 待支付状态
 */
public class PendingState implements OrderState {
    @Override
    public void handle(OrderContext context) {
        System.out.println("订单待支付,可以支付或取消");
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("支付成功,订单状态变为已支付");
        context.setState(new PaidState());
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("待支付状态不能发货");
    }
    
    @Override
    public void confirm(OrderContext context) {
        System.out.println("待支付状态不能确认收货");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消");
        context.setState(new CancelledState());
    }
}

/**
 * 已支付状态
 */
public class PaidState implements OrderState {
    @Override
    public void handle(OrderContext context) {
        System.out.println("订单已支付,可以发货或取消");
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已支付,无需重复支付");
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("发货成功,订单状态变为已发货");
        context.setState(new ShippedState());
    }
    
    @Override
    public void confirm(OrderContext context) {
        System.out.println("已支付状态不能确认收货");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("取消订单,退款处理中");
        context.setState(new CancelledState());
    }
}

/**
 * 已发货状态
 */
public class ShippedState implements OrderState {
    @Override
    public void handle(OrderContext context) {
        System.out.println("订单已发货,等待确认收货");
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("已发货状态不能支付");
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已发货,不能重复发货");
    }
    
    @Override
    public void confirm(OrderContext context) {
        System.out.println("确认收货,订单完成");
        context.setState(new CompletedState());
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("已发货状态不能取消,请联系客服");
    }
}

/**
 * 已完成状态
 */
public class CompletedState implements OrderState {
    @Override
    public void handle(OrderContext context) {
        System.out.println("订单已完成,可以评价");
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已完成,不能支付");
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已完成,不能发货");
    }
    
    @Override
    public void confirm(OrderContext context) {
        System.out.println("订单已完成,不能重复确认");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已完成,不能取消");
    }
}

/**
 * 已取消状态
 */
public class CancelledState implements OrderState {
    @Override
    public void handle(OrderContext context) {
        System.out.println("订单已取消,不能进行任何操作");
    }
    
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单已取消,不能支付");
    }
    
    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已取消,不能发货");
    }
    
    @Override
    public void confirm(OrderContext context) {
        System.out.println("订单已取消,不能确认收货");
    }
    
    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消,不能重复取消");
    }
}
3)定义环境类
java 复制代码
/**
 * 订单上下文类
 */
public class OrderContext {
    private OrderState state;
    private String orderId;
    
    public OrderContext(String orderId) {
        this.orderId = orderId;
        // 初始状态为待支付
        this.state = new PendingState();
    }
    
    public void setState(OrderState state) {
        this.state = state;
    }
    
    public OrderState getState() {
        return state;
    }
    
    // 委托给状态对象处理
    public void handle() {
        state.handle(this);
    }
    
    public void pay() {
        state.pay(this);
    }
    
    public void ship() {
        state.ship(this);
    }
    
    public void confirm() {
        state.confirm(this);
    }
    
    public void cancel() {
        state.cancel(this);
    }
    
    public String getOrderId() {
        return orderId;
    }
}
4)客户端测试
java 复制代码
/**
 * 测试类
 */
public class StatePatternDemo {
    public static void main(String[] args) {
        OrderContext order = new OrderContext("ORDER001");
        
        // 初始状态
        order.handle();
        order.pay();
        
        // 已支付状态
        order.handle();
        order.ship();
        
        // 已发货状态
        order.handle();
        order.confirm();
        
        // 已完成状态
        order.handle();
        order.cancel();
        
        System.out.println("====================================");
        
        // 测试异常流程
        OrderContext order2 = new OrderContext("ORDER002");
        order2.ship(); // 待支付状态尝试发货
        order2.cancel(); // 取消订单
        order2.pay(); // 已取消状态尝试支付
    }
}
4)测试结果

执行 main() 之后,结果如下所示:

整理完毕,完结撒花~🌻

参考地址:

1.状态模式(State模式),https://blog.csdn.net/qq_35784669/article/details/121238278

相关推荐
TL滕1 分钟前
从0开始学算法——第十八天(分治算法)
笔记·学习·算法
思成不止于此30 分钟前
【MySQL 零基础入门】MySQL 约束精讲(一):基础约束篇
数据库·笔记·sql·学习·mysql
小黄人软件1 小时前
【过度滥用眼】真正的理解,从闭眼开始:如何把“眼睛视觉依赖”降到最低,把大脑效率提到最高。【最少用眼的工作与学习体系】
学习
老华带你飞1 小时前
建筑材料管理|基于springboot 建筑材料管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习·spring
L.fountain2 小时前
图像自回归生成(Auto-regressive image generation)实战学习(一)
人工智能·深度学习·学习·计算机视觉·图像自回归
TL滕2 小时前
从0开始学算法——第十八天(分治算法练习)
笔记·学习·算法
蓝桉~MLGT3 小时前
Ai-Agent学习历程—— Agent认知框架
人工智能·学习
لا معنى له3 小时前
学习笔记:卷积神经网络(CNN)
人工智能·笔记·深度学习·神经网络·学习·cnn
لا معنى له4 小时前
学习笔记:注意力机制(Attention)、自注意力(Self-Attention)和多头注意力(Multi-Head Attention)
笔记·学习
走在路上的菜鸟4 小时前
Android学Dart学习笔记第十六节 类-构造方法
android·笔记·学习·flutter