设计模式之状态模式详解

48 阅读18分钟

深入理解设计模式之状态模式(State Pattern)

前言

在软件开发中,我们经常会遇到对象的行为依赖于其内部状态的场景。传统的做法是使用大量的if-else或switch-case语句来判断状态,这不仅让代码变得臃肿难维护,还违反了开闭原则。状态模式(State Pattern)正是为解决这类问题而设计的行为型模式。

本文将深入探讨状态模式的原理、实现方式,并结合订单系统、工作流引擎等实际生产场景,以及Spring State Machine等开源框架的应用,帮助读者全面掌握这一重要的设计模式。

一、什么是状态模式

1.1 定义

状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变其行为,看起来就像是改变了对象的类。状态模式将与特定状态相关的行为封装到独立的状态类中,使得对象在不同状态下具有不同的行为。

1.2 核心思想

状态模式的核心思想是:

  1. 将状态的判断逻辑转移到表示不同状态的类中
  2. 可以让对象的内部状态改变时改变其行为
  3. 状态转换的规则封装在状态类内部

1.3 状态模式的结构

            +------------------+
            |     Context      |
            +------------------+
            | - state: State   |
            +------------------+
            | + request()      |
            | + setState()     |
            +------------------+
                     |
                     | 持有
                     ↓
            +------------------+
            |   <<interface>>  |
            |      State       |
            +------------------+
            | + handle()       |
            +------------------+
                     △
                     |
         +-----------+-----------+
         |           |           |
   +-----------+ +-----------+ +-----------+
   |ConcreteA  | |ConcreteB  | |ConcreteC  |
   |State      | |State      | |State      |
   +-----------+ +-----------+ +-----------+
   |+ handle() | |+ handle() | |+ handle() |
   +-----------+ +-----------+ +-----------+

1.4 状态模式的角色

  1. Context(环境类):定义客户端感兴趣的接口,维护一个具体状态类的实例,这个实例定义当前状态。

  2. State(抽象状态类):定义一个接口,用于封装与Context的一个特定状态相关的行为。

  3. ConcreteState(具体状态类):实现抽象状态类中定义的接口,负责处理Context在该状态下的行为。

二、为什么需要状态模式

2.1 传统方式的问题

让我们先看一个不使用状态模式的订单处理示例:

/**
 * 传统方式:使用if-else处理状态
 */
public class OrderTraditional {
    private static final int STATE_NEW = 1;
    private static final int STATE_PAID = 2;
    private static final int STATE_SHIPPED = 3;
    private static final int STATE_DELIVERED = 4;
    private static final int STATE_CANCELLED = 5;

    private int state = STATE_NEW;

    public void pay() {
        if (state == STATE_NEW) {
            System.out.println("订单已支付");
            state = STATE_PAID;
        } else if (state == STATE_PAID) {
            System.out.println("订单已经支付过了");
        } else if (state == STATE_CANCELLED) {
            System.out.println("订单已取消,无法支付");
        } else {
            System.out.println("当前状态无法支付");
        }
    }

    public void ship() {
        if (state == STATE_PAID) {
            System.out.println("订单已发货");
            state = STATE_SHIPPED;
        } else if (state == STATE_NEW) {
            System.out.println("订单未支付,无法发货");
        } else if (state == STATE_SHIPPED) {
            System.out.println("订单已经发货了");
        } else {
            System.out.println("当前状态无法发货");
        }
    }

    public void cancel() {
        if (state == STATE_NEW || state == STATE_PAID) {
            System.out.println("订单已取消");
            state = STATE_CANCELLED;
        } else {
            System.out.println("当前状态无法取消");
        }
    }

    // 更多方法...每个方法都充斥着if-else判断
}

传统方式的问题:

  1. 代码臃肿,充斥着大量的条件判断
  2. 难以扩展,增加新状态需要修改多处代码
  3. 违反开闭原则和单一职责原则
  4. 状态转换逻辑分散,难以维护

2.2 状态模式的优势

  1. 封装性良好:将状态相关的行为封装到独立的类中
  2. 易于扩展:增加新状态只需添加新的状态类
  3. 消除条件语句:用多态替代条件判断
  4. 清晰的状态转换:状态转换规则集中管理
  5. 符合开闭原则:对扩展开放,对修改关闭

三、状态模式的实现

3.1 基础实现示例

让我们使用状态模式重构订单处理系统:

/**
 * 抽象状态接口
 */
interface OrderState {
    void pay(OrderContext context);
    void ship(OrderContext context);
    void deliver(OrderContext context);
    void cancel(OrderContext context);
    String getStateName();
}

/**
 * 环境类:订单上下文
 */
class OrderContext {
    private OrderState currentState;
    private String orderId;

    public OrderContext(String orderId) {
        this.orderId = orderId;
        // 初始状态为新建状态
        this.currentState = new NewOrderState();
        System.out.println("订单创建: " + orderId);
    }

    public void setState(OrderState state) {
        System.out.println("订单状态变更: " + currentState.getStateName() +
                         " -> " + state.getStateName());
        this.currentState = state;
    }

    public String getOrderId() {
        return orderId;
    }

    // 委托给当前状态处理
    public void pay() {
        currentState.pay(this);
    }

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

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

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

    public String getCurrentState() {
        return currentState.getStateName();
    }
}

/**
 * 具体状态类:新建状态
 */
class NewOrderState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("订单支付成功");
        context.setState(new PaidOrderState());
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("错误:订单未支付,无法发货");
    }

    @Override
    public void deliver(OrderContext context) {
        System.out.println("错误:订单未发货,无法确认收货");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消");
        context.setState(new CancelledOrderState());
    }

    @Override
    public String getStateName() {
        return "新建";
    }
}

/**
 * 具体状态类:已支付状态
 */
class PaidOrderState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("错误:订单已支付,无法重复支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("订单已发货,物流单号: SF" + System.currentTimeMillis());
        context.setState(new ShippedOrderState());
    }

    @Override
    public void deliver(OrderContext context) {
        System.out.println("错误:订单未发货,无法确认收货");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消,退款将在3-5个工作日内到账");
        context.setState(new CancelledOrderState());
    }

    @Override
    public String getStateName() {
        return "已支付";
    }
}

/**
 * 具体状态类:已发货状态
 */
class ShippedOrderState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("错误:订单已支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("错误:订单已发货");
    }

    @Override
    public void deliver(OrderContext context) {
        System.out.println("确认收货成功,感谢您的购买");
        context.setState(new DeliveredOrderState());
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("错误:订单已发货,如需退货请联系客服");
    }

    @Override
    public String getStateName() {
        return "已发货";
    }
}

/**
 * 具体状态类:已送达状态
 */
class DeliveredOrderState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("错误:订单已完成");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("错误:订单已完成");
    }

    @Override
    public void deliver(OrderContext context) {
        System.out.println("订单已完成");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("错误:订单已完成,如需退货请联系客服");
    }

    @Override
    public String getStateName() {
        return "已送达";
    }
}

/**
 * 具体状态类:已取消状态
 */
class CancelledOrderState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("错误:订单已取消,无法支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("错误:订单已取消,无法发货");
    }

    @Override
    public void deliver(OrderContext context) {
        System.out.println("错误:订单已取消");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("订单已取消");
    }

    @Override
    public String getStateName() {
        return "已取消";
    }
}

/**
 * 客户端测试
 */
public class StatePatternDemo {
    public static void main(String[] args) {
        // 创建订单
        OrderContext order = new OrderContext("ORDER_20231119001");
        System.out.println("当前状态: " + order.getCurrentState() + "\n");

        // 正常流程
        order.pay();
        System.out.println("当前状态: " + order.getCurrentState() + "\n");

        order.ship();
        System.out.println("当前状态: " + order.getCurrentState() + "\n");

        order.deliver();
        System.out.println("当前状态: " + order.getCurrentState() + "\n");

        // 尝试非法操作
        order.cancel();
        System.out.println("\n--- 异常流程测试 ---");

        // 测试异常流程
        OrderContext order2 = new OrderContext("ORDER_20231119002");
        order2.ship(); // 未支付就发货
        order2.pay();
        order2.cancel(); // 支付后取消
    }
}

输出结果:

订单创建: ORDER_20231119001
当前状态: 新建

订单支付成功
订单状态变更: 新建 -> 已支付
当前状态: 已支付

订单已发货,物流单号: SF1700380800123
订单状态变更: 已支付 -> 已发货
当前状态: 已发货

确认收货成功,感谢您的购买
订单状态变更: 已发货 -> 已送达
当前状态: 已送达

错误:订单已完成,如需退货请联系客服

--- 异常流程测试 ---
订单创建: ORDER_20231119002
错误:订单未支付,无法发货
订单支付成功
订单状态变更: 新建 -> 已支付
订单已取消,退款将在3-5个工作日内到账
订单状态变更: 已支付 -> 已取消

3.2 状态转换图(ASCII)

                    [新建订单]
                        |
                        | pay()
                        ↓
    cancel() ←---- [已支付] ----→ ship()
       |               |              ↓
       |               |         [已发货]
       |               |              |
       |               |              | deliver()
       |               |              ↓
       +------------→ [已取消]   [已送达]

四、生产环境中的实际应用

4.1 文档审批工作流

在企业应用中,文档审批是一个典型的状态模式应用场景:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 审批记录
 */
class ApprovalRecord {
    private String approver;
    private String action;
    private String comment;
    private Date timestamp;

    public ApprovalRecord(String approver, String action, String comment) {
        this.approver = approver;
        this.action = action;
        this.comment = comment;
        this.timestamp = new Date();
    }

    @Override
    public String toString() {
        return String.format("[%s] %s %s: %s", timestamp, approver, action, comment);
    }
}

/**
 * 文档审批状态接口
 */
interface DocumentState {
    void submit(DocumentContext context, String submitter);
    void approve(DocumentContext context, String approver, String comment);
    void reject(DocumentContext context, String approver, String comment);
    void revoke(DocumentContext context);
    void publish(DocumentContext context);
    String getStateName();
}

/**
 * 文档上下文
 */
class DocumentContext {
    private String documentId;
    private String title;
    private String content;
    private DocumentState currentState;
    private List<ApprovalRecord> approvalHistory;
    private int currentApprovalLevel;
    private static final int MAX_APPROVAL_LEVEL = 3; // 需要3级审批

    public DocumentContext(String documentId, String title, String content) {
        this.documentId = documentId;
        this.title = title;
        this.content = content;
        this.currentState = new DraftState();
        this.approvalHistory = new ArrayList<>();
        this.currentApprovalLevel = 0;
        System.out.println("文档创建: " + title);
    }

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

    public void addApprovalRecord(ApprovalRecord record) {
        approvalHistory.add(record);
    }

    public void incrementApprovalLevel() {
        currentApprovalLevel++;
    }

    public void resetApprovalLevel() {
        currentApprovalLevel = 0;
    }

    public boolean isFullyApproved() {
        return currentApprovalLevel >= MAX_APPROVAL_LEVEL;
    }

    public int getCurrentApprovalLevel() {
        return currentApprovalLevel;
    }

    public int getMaxApprovalLevel() {
        return MAX_APPROVAL_LEVEL;
    }

    // 委托给状态对象
    public void submit(String submitter) {
        currentState.submit(this, submitter);
    }

    public void approve(String approver, String comment) {
        currentState.approve(this, approver, comment);
    }

    public void reject(String approver, String comment) {
        currentState.reject(this, approver, comment);
    }

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

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

    public String getStateName() {
        return currentState.getStateName();
    }

    public void printApprovalHistory() {
        System.out.println("\n审批历史:");
        for (ApprovalRecord record : approvalHistory) {
            System.out.println(record);
        }
    }
}

/**
 * 草稿状态
 */
class DraftState implements DocumentState {
    @Override
    public void submit(DocumentContext context, String submitter) {
        System.out.println(submitter + " 提交文档进行审批");
        context.addApprovalRecord(new ApprovalRecord(submitter, "提交审批", "文档已提交"));
        context.setState(new PendingApprovalState());
    }

    @Override
    public void approve(DocumentContext context, String approver, String comment) {
        System.out.println("错误:草稿状态无法审批");
    }

    @Override
    public void reject(DocumentContext context, String approver, String comment) {
        System.out.println("错误:草稿状态无法驳回");
    }

    @Override
    public void revoke(DocumentContext context) {
        System.out.println("错误:草稿状态无需撤回");
    }

    @Override
    public void publish(DocumentContext context) {
        System.out.println("错误:草稿状态无法发布");
    }

    @Override
    public String getStateName() {
        return "草稿";
    }
}

/**
 * 待审批状态
 */
class PendingApprovalState implements DocumentState {
    @Override
    public void submit(DocumentContext context, String submitter) {
        System.out.println("错误:文档已在审批中");
    }

    @Override
    public void approve(DocumentContext context, String approver, String comment) {
        context.incrementApprovalLevel();
        System.out.println(approver + " 审批通过 (第" + context.getCurrentApprovalLevel() +
                         "级/共" + context.getMaxApprovalLevel() + "级)");
        context.addApprovalRecord(new ApprovalRecord(approver, "审批通过", comment));

        if (context.isFullyApproved()) {
            System.out.println("所有审批已完成,文档进入待发布状态");
            context.setState(new ApprovedState());
        }
    }

    @Override
    public void reject(DocumentContext context, String approver, String comment) {
        System.out.println(approver + " 驳回审批");
        context.addApprovalRecord(new ApprovalRecord(approver, "驳回", comment));
        context.resetApprovalLevel();
        context.setState(new RejectedState());
    }

    @Override
    public void revoke(DocumentContext context) {
        System.out.println("撤回审批,文档返回草稿状态");
        context.addApprovalRecord(new ApprovalRecord("系统", "撤回", "作者撤回审批"));
        context.resetApprovalLevel();
        context.setState(new DraftState());
    }

    @Override
    public void publish(DocumentContext context) {
        System.out.println("错误:文档审批未完成,无法发布");
    }

    @Override
    public String getStateName() {
        return "待审批";
    }
}

/**
 * 审批通过状态
 */
class ApprovedState implements DocumentState {
    @Override
    public void submit(DocumentContext context, String submitter) {
        System.out.println("错误:文档已审批通过");
    }

    @Override
    public void approve(DocumentContext context, String approver, String comment) {
        System.out.println("错误:文档已审批通过");
    }

    @Override
    public void reject(DocumentContext context, String approver, String comment) {
        System.out.println("错误:文档已审批通过");
    }

    @Override
    public void revoke(DocumentContext context) {
        System.out.println("撤回审批,文档返回草稿状态");
        context.addApprovalRecord(new ApprovalRecord("系统", "撤回", "作者撤回审批"));
        context.resetApprovalLevel();
        context.setState(new DraftState());
    }

    @Override
    public void publish(DocumentContext context) {
        System.out.println("文档已发布");
        context.addApprovalRecord(new ApprovalRecord("系统", "发布", "文档已正式发布"));
        context.setState(new PublishedState());
    }

    @Override
    public String getStateName() {
        return "审批通过";
    }
}

/**
 * 已驳回状态
 */
class RejectedState implements DocumentState {
    @Override
    public void submit(DocumentContext context, String submitter) {
        System.out.println(submitter + " 重新提交文档进行审批");
        context.addApprovalRecord(new ApprovalRecord(submitter, "重新提交", "文档已修改并重新提交"));
        context.setState(new PendingApprovalState());
    }

    @Override
    public void approve(DocumentContext context, String approver, String comment) {
        System.out.println("错误:已驳回的文档无法直接审批");
    }

    @Override
    public void reject(DocumentContext context, String approver, String comment) {
        System.out.println("错误:文档已处于驳回状态");
    }

    @Override
    public void revoke(DocumentContext context) {
        System.out.println("文档返回草稿状态");
        context.setState(new DraftState());
    }

    @Override
    public void publish(DocumentContext context) {
        System.out.println("错误:已驳回的文档无法发布");
    }

    @Override
    public String getStateName() {
        return "已驳回";
    }
}

/**
 * 已发布状态
 */
class PublishedState implements DocumentState {
    @Override
    public void submit(DocumentContext context, String submitter) {
        System.out.println("错误:文档已发布,无法提交");
    }

    @Override
    public void approve(DocumentContext context, String approver, String comment) {
        System.out.println("错误:文档已发布");
    }

    @Override
    public void reject(DocumentContext context, String approver, String comment) {
        System.out.println("错误:文档已发布");
    }

    @Override
    public void revoke(DocumentContext context) {
        System.out.println("错误:已发布的文档无法撤回");
    }

    @Override
    public void publish(DocumentContext context) {
        System.out.println("文档已发布");
    }

    @Override
    public String getStateName() {
        return "已发布";
    }
}

/**
 * 工作流测试
 */
public class WorkflowStateDemo {
    public static void main(String[] args) {
        DocumentContext doc = new DocumentContext("DOC001", "年度报告", "这是年度报告内容...");
        System.out.println("当前状态: " + doc.getStateName() + "\n");

        // 提交审批
        doc.submit("张三");
        System.out.println("当前状态: " + doc.getStateName() + "\n");

        // 第一级审批
        doc.approve("经理李四", "内容详实,同意");
        System.out.println("当前状态: " + doc.getStateName() + "\n");

        // 第二级审批
        doc.approve("总监王五", "格式规范,同意");
        System.out.println("当前状态: " + doc.getStateName() + "\n");

        // 第三级审批
        doc.approve("总经理赵六", "最终批准");
        System.out.println("当前状态: " + doc.getStateName() + "\n");

        // 发布文档
        doc.publish();
        System.out.println("当前状态: " + doc.getStateName());

        // 打印审批历史
        doc.printApprovalHistory();

        System.out.println("\n\n--- 驳回流程测试 ---");
        DocumentContext doc2 = new DocumentContext("DOC002", "项目方案", "项目方案内容...");
        doc2.submit("李明");
        doc2.approve("经理", "第一级通过");
        doc2.reject("总监", "方案需要完善细节");
        System.out.println("当前状态: " + doc2.getStateName());
        doc2.printApprovalHistory();
    }
}

4.2 TCP连接状态管理

TCP协议的连接管理是状态模式的经典应用:

/**
 * TCP连接状态接口
 */
interface TCPState {
    void open(TCPConnection connection);
    void close(TCPConnection connection);
    void acknowledge(TCPConnection connection);
    String getStateName();
}

/**
 * TCP连接上下文
 */
class TCPConnection {
    private TCPState state;
    private String connectionId;

    public TCPConnection(String connectionId) {
        this.connectionId = connectionId;
        this.state = new TCPClosedState();
        System.out.println("TCP连接创建: " + connectionId);
    }

    public void setState(TCPState state) {
        System.out.println("状态转换: " + this.state.getStateName() +
                         " -> " + state.getStateName());
        this.state = state;
    }

    public void open() {
        state.open(this);
    }

    public void close() {
        state.close(this);
    }

    public void acknowledge() {
        state.acknowledge(this);
    }

    public String getConnectionId() {
        return connectionId;
    }

    public String getStateName() {
        return state.getStateName();
    }
}

/**
 * 关闭状态
 */
class TCPClosedState implements TCPState {
    @Override
    public void open(TCPConnection connection) {
        System.out.println("发送SYN,请求建立连接");
        connection.setState(new TCPListenState());
    }

    @Override
    public void close(TCPConnection connection) {
        System.out.println("连接已关闭");
    }

    @Override
    public void acknowledge(TCPConnection connection) {
        System.out.println("错误:连接未打开");
    }

    @Override
    public String getStateName() {
        return "CLOSED";
    }
}

/**
 * 监听状态
 */
class TCPListenState implements TCPState {
    @Override
    public void open(TCPConnection connection) {
        System.out.println("收到SYN-ACK,发送ACK");
        connection.setState(new TCPEstablishedState());
    }

    @Override
    public void close(TCPConnection connection) {
        System.out.println("关闭连接");
        connection.setState(new TCPClosedState());
    }

    @Override
    public void acknowledge(TCPConnection connection) {
        System.out.println("等待连接确认");
    }

    @Override
    public String getStateName() {
        return "LISTEN";
    }
}

/**
 * 已建立状态
 */
class TCPEstablishedState implements TCPState {
    @Override
    public void open(TCPConnection connection) {
        System.out.println("连接已建立");
    }

    @Override
    public void close(TCPConnection connection) {
        System.out.println("发送FIN,开始关闭连接");
        connection.setState(new TCPClosedState());
    }

    @Override
    public void acknowledge(TCPConnection connection) {
        System.out.println("发送ACK确认");
    }

    @Override
    public String getStateName() {
        return "ESTABLISHED";
    }
}

/**
 * TCP状态示例
 */
public class TCPStateDemo {
    public static void main(String[] args) {
        TCPConnection connection = new TCPConnection("192.168.1.100:8080");
        System.out.println("初始状态: " + connection.getStateName() + "\n");

        // 三次握手
        connection.open();  // 客户端发送SYN
        connection.open();  // 收到SYN-ACK,发送ACK
        System.out.println("当前状态: " + connection.getStateName() + "\n");

        // 数据传输
        connection.acknowledge();
        System.out.println();

        // 关闭连接
        connection.close();
        System.out.println("最终状态: " + connection.getStateName());
    }
}

五、开源框架中的状态模式应用

5.1 Spring State Machine

Spring State Machine是Spring官方提供的状态机框架,是状态模式在企业级应用中的典型实现。

/**
 * 简化的Spring State Machine使用示例
 * 实际使用需要添加Spring State Machine依赖
 */

// 定义状态枚举
enum OrderStatus {
    UNPAID,      // 未支付
    PAID,        // 已支付
    SHIPPED,     // 已发货
    DELIVERED,   // 已送达
    CANCELLED    // 已取消
}

// 定义事件枚举
enum OrderEvent {
    PAY,         // 支付
    SHIP,        // 发货
    DELIVER,     // 送达
    CANCEL       // 取消
}

/**
 * 模拟Spring State Machine的配置
 */
class OrderStateMachineConfig {

    /**
     * 配置状态转换
     */
    public void configureTransitions() {
        // UNPAID -> PAY -> PAID
        // PAID -> SHIP -> SHIPPED
        // SHIPPED -> DELIVER -> DELIVERED
        // UNPAID/PAID -> CANCEL -> CANCELLED

        System.out.println("状态机配置:");
        System.out.println("UNPAID --[PAY]--> PAID");
        System.out.println("PAID --[SHIP]--> SHIPPED");
        System.out.println("SHIPPED --[DELIVER]--> DELIVERED");
        System.out.println("UNPAID/PAID --[CANCEL]--> CANCELLED");
    }

    /**
     * 配置状态监听器
     */
    public void configureStateListener() {
        // 状态进入时的处理
        System.out.println("\n配置状态监听器:");
        System.out.println("- onEntry: 进入状态时触发");
        System.out.println("- onExit: 离开状态时触发");
    }

    /**
     * 配置转换守卫(条件判断)
     */
    public void configureGuards() {
        System.out.println("\n配置转换守卫:");
        System.out.println("- 支付前检查库存");
        System.out.println("- 发货前检查地址");
    }

    /**
     * 配置动作
     */
    public void configureActions() {
        System.out.println("\n配置状态动作:");
        System.out.println("- 支付成功后发送通知");
        System.out.println("- 发货时生成物流单");
        System.out.println("- 送达后发送评价邀请");
    }
}

/**
 * Spring State Machine使用示例
 */
public class SpringStateMachineDemo {
    public static void main(String[] args) {
        System.out.println("===== Spring State Machine 概念演示 =====\n");

        OrderStateMachineConfig config = new OrderStateMachineConfig();
        config.configureTransitions();
        config.configureStateListener();
        config.configureGuards();
        config.configureActions();

        System.out.println("\n\n===== 状态转换示例 =====");
        simulateOrderFlow();
    }

    private static void simulateOrderFlow() {
        System.out.println("\n订单生命周期:");
        System.out.println("1. 创建订单 -> UNPAID");
        System.out.println("2. 触发PAY事件 -> PAID");
        System.out.println("3. 触发SHIP事件 -> SHIPPED");
        System.out.println("4. 触发DELIVER事件 -> DELIVERED");

        System.out.println("\nSpring State Machine的优势:");
        System.out.println("✓ 声明式配置状态转换");
        System.out.println("✓ 支持状态持久化");
        System.out.println("✓ 提供状态监听和拦截");
        System.out.println("✓ 支持嵌套状态机");
        System.out.println("✓ 集成Spring生态");
    }
}

5.2 实际Spring State Machine配置示例

/**
 * 实际的Spring State Machine配置类结构
 * (需要添加相关依赖和注解)
 */

/*
@Configuration
@EnableStateMachine
public class ActualStateMachineConfig
    extends StateMachineConfigurerAdapter<OrderStatus, OrderEvent> {

    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states)
            throws Exception {
        states
            .withStates()
            .initial(OrderStatus.UNPAID)
            .states(EnumSet.allOf(OrderStatus.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(OrderStatus.UNPAID).target(OrderStatus.PAID)
                .event(OrderEvent.PAY)
                .guard(paymentGuard())
                .action(paymentAction())
            .and()
            .withExternal()
                .source(OrderStatus.PAID).target(OrderStatus.SHIPPED)
                .event(OrderEvent.SHIP)
                .action(shipAction())
            .and()
            .withExternal()
                .source(OrderStatus.SHIPPED).target(OrderStatus.DELIVERED)
                .event(OrderEvent.DELIVER)
                .action(deliverAction());
    }

    @Bean
    public Guard<OrderStatus, OrderEvent> paymentGuard() {
        return context -> {
            // 支付前的条件检查
            return checkInventory() && checkUserBalance();
        };
    }

    @Bean
    public Action<OrderStatus, OrderEvent> paymentAction() {
        return context -> {
            // 支付成功后的动作
            sendPaymentNotification();
            updateInventory();
        };
    }
}
*/

5.3 Java线程状态

Java线程的状态转换也是状态模式的应用:

/**
 * Java线程状态演示
 */
public class ThreadStateDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Java线程状态转换图:\n");
        printThreadStateTransition();

        System.out.println("\n\n实际线程状态演示:");
        demonstrateThreadStates();
    }

    private static void printThreadStateTransition() {
        System.out.println("        [NEW]");
        System.out.println("          |");
        System.out.println("          | start()");
        System.out.println("          ↓");
        System.out.println("      [RUNNABLE] ←------------------+");
        System.out.println("          |                          |");
        System.out.println("          | wait()/join()            | notify()/");
        System.out.println("          ↓                          | notifyAll()");
        System.out.println("       [WAITING] -------------------+");
        System.out.println("          |");
        System.out.println("          | sleep()/wait(timeout)");
        System.out.println("          ↓");
        System.out.println("   [TIMED_WAITING]");
        System.out.println("          |");
        System.out.println("          | 等待锁");
        System.out.println("          ↓");
        System.out.println("      [BLOCKED]");
        System.out.println("          |");
        System.out.println("          | 执行完毕");
        System.out.println("          ↓");
        System.out.println("     [TERMINATED]");
    }

    private static void demonstrateThreadStates() throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                System.out.println("线程开始执行");
                Thread.sleep(2000); // TIMED_WAITING
                System.out.println("线程执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // NEW状态
        System.out.println("创建线程后: " + thread.getState());

        // 启动线程
        thread.start();
        Thread.sleep(100);
        System.out.println("启动线程后: " + thread.getState());

        // TIMED_WAITING状态
        Thread.sleep(500);
        System.out.println("sleep期间: " + thread.getState());

        // 等待线程结束
        thread.join();
        System.out.println("线程结束后: " + thread.getState());
    }
}

六、状态模式的最佳实践

6.1 设计原则

  1. 单一职责:每个状态类只负责一个状态的行为
  2. 开闭原则:添加新状态不需要修改已有代码
  3. 状态封装:状态转换逻辑封装在状态类内部
  4. 上下文简洁:Context类只负责维护当前状态

6.2 何时使用状态模式

适用场景:

  1. 对象行为依赖于状态,且状态会在运行时改变
  2. 代码中包含大量条件判断,且这些判断依赖于对象状态
  3. 状态转换规则复杂,需要集中管理
  4. 需要避免重复的状态判断代码

不适用场景:

  1. 状态很少(只有2-3个状态)
  2. 状态转换规则简单
  3. 状态类会导致类数量激增但收益不大

6.3 实现技巧

6.3.1 状态单例模式
/**
 * 使用单例模式优化状态对象
 * 避免重复创建状态对象
 */
class SingletonOrderState {
    private static final NewOrderState NEW_STATE = new NewOrderState();
    private static final PaidOrderState PAID_STATE = new PaidOrderState();
    private static final ShippedOrderState SHIPPED_STATE = new ShippedOrderState();

    public static NewOrderState getNewState() {
        return NEW_STATE;
    }

    public static PaidOrderState getPaidState() {
        return PAID_STATE;
    }

    public static ShippedOrderState getShippedState() {
        return SHIPPED_STATE;
    }
}

/**
 * 使用单例状态
 */
class OptimizedOrderContext {
    private OrderState state;

    public OptimizedOrderContext() {
        this.state = SingletonOrderState.getNewState();
    }

    public void pay() {
        state.pay(this);
        // 使用单例状态
        setState(SingletonOrderState.getPaidState());
    }

    public void setState(OrderState state) {
        this.state = state;
    }
}
6.3.2 状态转换表
import java.util.HashMap;
import java.util.Map;

/**
 * 使用状态转换表管理复杂的状态转换
 */
class StateTransitionTable {
    private Map<String, Map<String, OrderState>> transitions;

    public StateTransitionTable() {
        transitions = new HashMap<>();
        initializeTransitions();
    }

    private void initializeTransitions() {
        // NEW状态的转换
        Map<String, OrderState> fromNew = new HashMap<>();
        fromNew.put("PAY", SingletonOrderState.getPaidState());
        transitions.put("NEW", fromNew);

        // PAID状态的转换
        Map<String, OrderState> fromPaid = new HashMap<>();
        fromPaid.put("SHIP", SingletonOrderState.getShippedState());
        transitions.put("PAID", fromPaid);

        // 更多状态转换...
    }

    public OrderState getNextState(String currentState, String event) {
        Map<String, OrderState> stateTransitions = transitions.get(currentState);
        if (stateTransitions != null) {
            return stateTransitions.get(event);
        }
        return null;
    }

    public boolean canTransition(String currentState, String event) {
        return getNextState(currentState, event) != null;
    }
}
6.3.3 状态持久化
/**
 * 支持状态持久化的订单上下文
 */
class PersistentOrderContext {
    private String orderId;
    private OrderState state;
    private StateRepository repository;

    public PersistentOrderContext(String orderId, StateRepository repository) {
        this.orderId = orderId;
        this.repository = repository;
        // 从数据库加载状态
        loadState();
    }

    private void loadState() {
        String stateName = repository.loadState(orderId);
        this.state = createStateFromName(stateName);
    }

    public void setState(OrderState newState) {
        this.state = newState;
        // 保存状态到数据库
        repository.saveState(orderId, newState.getStateName());
    }

    private OrderState createStateFromName(String stateName) {
        // 根据状态名称创建状态对象
        switch (stateName) {
            case "新建": return SingletonOrderState.getNewState();
            case "已支付": return SingletonOrderState.getPaidState();
            // 更多状态...
            default: return SingletonOrderState.getNewState();
        }
    }
}

/**
 * 状态仓储接口
 */
interface StateRepository {
    String loadState(String orderId);
    void saveState(String orderId, String stateName);
}

七、状态模式与策略模式的区别

状态模式和策略模式在结构上很相似,但用途不同:

状态模式 (State Pattern):
目的:根据状态改变行为
特点:
  - 状态之间可以相互转换
  - 状态转换通常由状态对象自己决定
  - 客户端通常不知道具体状态类
  - 重点在"是什么状态"

示例:
  订单的状态:新建 -> 已支付 -> 已发货
  状态之间有转换关系

         Context
            |
            | 持有并会改变
            ↓
         State A ──→ State B ──→ State C


策略模式 (Strategy Pattern):
目的:封装算法,使它们可以互换
特点:
  - 策略之间是平等的,不互相转换
  - 策略选择通常由客户端决定
  - 客户端需要知道所有策略
  - 重点在"怎么做"

示例:
  支付方式:支付宝、微信、银行卡
  策略之间相互独立

         Context
            |
            | 持有但不改变
            ↓
      Strategy接口
         ↗  ↑  ↖
   Strategy A  B  C

八、状态模式的注意事项

8.1 常见陷阱

  1. 状态类爆炸:状态过多导致类数量激增
// 解决方案:合并相似状态或使用状态组合
class CompositeState implements OrderState {
    private List<OrderState> states = new ArrayList<>();

    public void addState(OrderState state) {
        states.add(state);
    }
}
  1. 状态转换混乱:缺乏清晰的状态转换规则
// 解决方案:使用状态转换表或状态机框架
// 绘制状态转换图,明确所有可能的转换
  1. 状态共享问题:使用单例状态时的并发问题
// 解决方案:确保状态类是无状态的(stateless)
// 所有数据都存储在Context中
class StatelessOrderState implements OrderState {
    // 不包含任何实例变量
    // 所有操作都基于传入的context

    @Override
    public void pay(OrderContext context) {
        // 使用context中的数据,不使用自身状态
    }
}

8.2 性能优化

  1. 使用享元模式:共享状态对象
  2. 延迟加载:按需创建状态对象
  3. 状态缓存:缓存频繁使用的状态
/**
 * 状态工厂 + 缓存
 */
class StateFactory {
    private static Map<String, OrderState> stateCache = new ConcurrentHashMap<>();

    public static OrderState getState(String stateName) {
        return stateCache.computeIfAbsent(stateName, key -> {
            switch (key) {
                case "NEW": return new NewOrderState();
                case "PAID": return new PaidOrderState();
                default: throw new IllegalArgumentException("Unknown state: " + key);
            }
        });
    }
}

九、总结

状态模式是处理对象状态变化的强大工具,它通过将状态相关的行为封装到独立的状态类中,消除了复杂的条件判断,提高了代码的可维护性和扩展性。

9.1 核心要点

  1. 消除条件判断:用多态替代if-else
  2. 封装状态行为:每个状态类负责自己的行为
  3. 清晰的状态转换:状态转换规则明确
  4. 易于扩展:添加新状态不影响现有代码

9.2 优缺点总结

优点:

  • 结构清晰,将状态相关行为局部化
  • 消除了庞大的条件分支语句
  • 易于增加新的状态
  • 状态转换显式化
  • 符合单一职责原则和开闭原则

缺点:

  • 会增加系统类的数量
  • 状态模式的结构与实现较为复杂
  • 如果状态较少,使用状态模式会显得繁琐
  • 状态转换逻辑分散可能导致难以理解整体流程

9.3 使用建议

  1. 适度使用:状态少于5个时考虑简单的if-else
  2. 状态可视化:绘制状态转换图,便于理解和维护
  3. 使用框架:复杂场景考虑使用Spring State Machine等框架
  4. 状态持久化:关键业务状态需要持久化到数据库
  5. 日志记录:记录所有状态转换,便于问题排查

9.4 最佳实践

  • 小型项目:状态简单时使用枚举 + switch即可
  • 中型项目:状态复杂时使用状态模式
  • 大型项目:使用状态机框架(Spring State Machine)
  • 分布式系统:考虑使用工作流引擎(Activiti、Camunda)

状态模式不仅仅是一种设计模式,更是一种面向对象的思维方式。通过合理运用状态模式,我们可以让代码更加优雅、更易维护。希望本文能帮助你在实际项目中更好地应用状态模式。