状态模式原理剖析

《状态模式原理剖析》

状态模式(State Pattern) 是一种行为设计模式,它允许对象在其内部状态 改变时改变其行为。换句话说,当对象状态发生变化时,它的行为也会随之变化。

通过状态模式,可以消除通过 if-else 或 switch-case 来判断状态的需要。每个状态的行为封装在独立的类中

核心思想

状态模式将对象的不同状态封装成独立的类,并让对象在不同的状态下有不同的行为。状态模式通过将状态的行为和逻辑封装在状态类中,使得状态之间的转换变得清晰、易扩展。

UML 类图:状态模式

角色说明

  1. Context(上下文类)
    • 持有一个 State 对象,表示当前的状态。
    • 负责将状态的转换委托给具体的状态类。
  2. State(抽象状态类)
    • 定义了一个 handle() 方法,用于处理当前状态的逻辑。
  3. ConcreteState(具体状态类)
    • 实现 State 接口,负责在具体状态下的行为。
    • 不同的具体状态类表示对象在不同状态下的不同行为。

案例:订单状态管理

场景描述:

在电商平台或者订餐系统中,订单的状态是一个典型的使用状态模式的场景。订单的状态通常包括以下几种:

  • 新订单NewOrder):订单刚创建。
  • 已付款Paid):订单已付款,等待发货。
  • 已发货Shipped):订单已经发货,等待确认收货。
  • 已完成Completed):订单交易完成。
  • 取消订单Cancelled):订单被取消。

每个订单的状态都会影响订单的行为。例如,只有在新订单 状态下,用户才可以取消订单;在已付款 状态下,用户不能取消订单,但可以查询发货状态;而在已完成取消状态下,订单是不可修改的。

状态模式处理的好处:

  1. 避免复杂的 if-else 条件判断 :不同状态下的订单行为各不相同,使用状态模式可以避免在代码中出现大量的 if-else 条件判断(如:if(order.status == "paid") { ... } else if(order.status == "shipped") { ... })。
  2. 状态行为封装:将每种状态的行为封装到相应的状态类中,使得状态切换清晰,便于维护和扩展。
  3. 提高扩展性:当需要新增或修改订单状态时,可以通过新增状态类而不影响现有代码逻辑,符合开闭原则。

代码实现:订单状态管理

Step 1: 定义状态接口

我们首先定义一个 OrderState 接口,声明了订单状态下的所有可能的行为,比如支付、发货、取消和完成

java 复制代码
// 状态接口:订单状态
public interface OrderState {
    void pay(OrderContext context);
    void ship(OrderContext context);
    void cancel(OrderContext context);
    void complete(OrderContext context);
}

Step 2: 实现具体的状态类

新订单状态(NewOrderState)

当订单处于新订单状态时,可以进行支付或取消操作,但不能发货或完成。

java 复制代码
// 具体状态类:新订单状态
public class NewOrderState implements OrderState {

    @Override
    public void pay(OrderContext context) {
        System.out.println("Order paid. Moving to Paid state.");
        context.setState(new PaidOrderState());
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("Cannot ship order. Order is not paid yet.");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("Order cancelled.");
        context.setState(new CancelledOrderState());
    }

    @Override
    public void complete(OrderContext context) {
        System.out.println("Cannot complete order. Order is not paid yet.");
    }
}

已付款状态(PaidOrderState)

当订单处于已付款状态时,可以发货,但不能取消订单。

java 复制代码
// 具体状态类:已付款状态
public class PaidOrderState implements OrderState {

    @Override
    public void pay(OrderContext context) {
        System.out.println("Order is already paid.");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("Order shipped. Moving to Shipped state.");
        context.setState(new ShippedOrderState());
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("Cannot cancel. Order is already paid.");
    }

    @Override
    public void complete(OrderContext context) {
        System.out.println("Cannot complete order. Order is not shipped yet.");
    }
}

已发货状态(ShippedOrderState)

当订单处于已发货状态时,可以完成订单,但不能再发货或取消订单。

java 复制代码
// 具体状态类:已发货状态
public class ShippedOrderState implements OrderState {

    @Override
    public void pay(OrderContext context) {
        System.out.println("Order is already paid and shipped.");
    }

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

    @Override
    public void cancel(OrderContext context) {
        System.out.println("Cannot cancel. Order is already shipped.");
    }

    @Override
    public void complete(OrderContext context) {
        System.out.println("Order completed. Moving to Completed state.");
        context.setState(new CompletedOrderState());
    }
}

已完成状态(CompletedOrderState)

订单已经完成后,所有操作都无法再进行。

java 复制代码
// 具体状态类:已完成状态
public class CompletedOrderState implements OrderState {

    @Override
    public void pay(OrderContext context) {
        System.out.println("Cannot pay. Order is already completed.");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("Cannot ship. Order is already completed.");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("Cannot cancel. Order is already completed.");
    }

    @Override
    public void complete(OrderContext context) {
        System.out.println("Order is already completed.");
    }
}

取消订单状态(CancelledOrderState)

订单被取消后,所有操作都无法再进行。

java 复制代码
// 具体状态类:取消订单状态
public class CancelledOrderState implements OrderState {

    @Override
    public void pay(OrderContext context) {
        System.out.println("Cannot pay. Order is cancelled.");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("Cannot ship. Order is cancelled.");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("Order is already cancelled.");
    }

    @Override
    public void complete(OrderContext context) {
        System.out.println("Cannot complete. Order is cancelled.");
    }
}

Step 3: 创建上下文类

OrderContext 持有订单的当前状态,并且通过调用当前状态的行为方法来执行操作。

java 复制代码
// 上下文类:订单上下文
public class OrderContext {
    private OrderState currentState;

    public OrderContext() {
        this.currentState = new NewOrderState(); // 初始状态为新订单
    }

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

    public void pay() {
        currentState.pay(this);
    }

    public void ship() {
        currentState.ship(this);
    }

    public void cancel() {
        currentState.cancel(this);
    }

    public void complete() {
        currentState.complete(this);
    }
}

Step 4: 测试状态模式

java 复制代码
public class OrderStatePatternDemo {

    public static void main(String[] args) {
        OrderContext order = new OrderContext();

        // 订单状态:新订单
        order.pay();       // 支付订单
        order.ship();      // 发货订单
        order.complete();  // 完成订单

        // 尝试取消已完成订单
        order.cancel();    // 无法取消已完成订单
    }
}

输出结果

java 复制代码
Order paid. Moving to Paid state.
Order shipped. Moving to Shipped state.
Order completed. Moving to Completed state.
Cannot cancel. Order is already completed.

状态模式解决的问题

  1. 避免条件判断的复杂性
    • 如果不使用状态模式,代码中会充满大量的 if-elseswitch-case 条件判断。状态模式将这些判断逻辑分散到各个状态类中,避免了复杂的条件分支。
  2. 清晰的状态转换逻辑
    • 状态模式将状态和行为封装在状态类中,所有的状态转换逻辑都非常清晰。状态的变化和行为的变化是分开的,彼此不干扰。
  3. 遵循开闭原则
    • 新的状态和行为可以通过增加新的状态类实现,而不需要修改已有的状态逻辑,符合开闭原则,便于扩展。

总结

状态模式 是一种强大的设计模式,尤其适合在对象状态频繁变化行为因状态不同而变化的场景中。在订单状态管理的案例中,状态模式帮助我们将订单在不同状态下的行为封装起来,使得代码更加灵活、清晰,同时提高了代码的可扩展性。

通过状态模式,开发者可以轻松应对复杂的状态转换逻辑,并在不修改已有代码的前提下添加新的状态,保证系统的灵活性和扩展性。

优点

  1. 遵循开闭原则
    • 新增状态类时,不需要修改现有的上下文类或状态类,可以轻松扩展系统的状态和行为。
  2. 清晰的状态转换
    • 将状态转换的逻辑封装在各自的状态类中,使得状态之间的切换更加清晰且易于维护。
  3. 消除复杂的条件判断
    • 通过状态模式,消除了通过 if-elseswitch-case 来判断状态的需要。每个状态的行为封装在独立的类中。

缺点

  1. 类的数量增加
    • 每种状态都有一个对应的类,可能导致类的数量急剧增加,增加系统的复杂性。
  2. 状态切换逻辑可能复杂
    • 如果系统中状态过多,且状态间的转换规则复杂,可能会增加状态管理的难度。
相关推荐
言慢行善4 分钟前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星9 分钟前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟28 分钟前
操作系统之虚拟内存
java·服务器·网络
Tong Z29 分钟前
常见的限流算法和实现原理
java·开发语言
凭君语未可33 分钟前
Java 中的实现类是什么
java·开发语言
He少年35 分钟前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
AwesomeCPA41 分钟前
Miaoduo MCP 使用指南(VDI内网环境)
前端·ui·ai编程
克里斯蒂亚诺更新1 小时前
myeclipse的pojie
java·ide·myeclipse
迷藏4941 小时前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4941 小时前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链