前言
以前在做支付系统的入金模块时,遇到了一个经典问题:交易状态流转。
你以为状态机就是 if-else 一把梭?年轻人,图样图森破。当你的状态从 3 个变成 10 个,事件从 5 个变成 20 个,你就会发现自己写的代码比《百年孤独》里的家谱还难理清。
今天,我们就来聊聊如何优雅地实现一个状态机,让你的代码不至于成为同事口中的"祖传屎山"。
什么是状态机?
概念定义
状态机(State Machine),全称是有限状态机(Finite State Machine,简称 FSM),是一种数学计算模型。它由以下几个核心要素组成:
| 要素 | 说明 | 支付场景示例 |
|---|---|---|
| 状态(State) | 系统在某一时刻的状况 | 待验证、处理中、成功、失败 |
| 事件(Event) | 触发状态变化的外部输入 | 用户提交、审核通过、支付回调 |
| 转换(Transition) | 从一个状态到另一个状态的变化 | 待验证 → 已验证 |
| 动作(Action) | 状态转换时执行的操作 | 发送通知、更新余额、记录日志 |
| 守卫(Guard) | 转换前的条件检查 | 余额是否充足、账户是否激活 |
用人话说:状态机就是一套规则,定义了"在什么状态下,发生什么事件,会转换到什么状态,并且执行什么动作"。
为什么状态机如此重要?(尤其对于支付系统)
1. 业务逻辑的"契约化"
没有状态机的代码通常长这样:
// 💀 地狱级代码示例
public void processPayment(Payment payment, String action) {
if (payment.getStatus().equals("PENDING") && action.equals("approve")) {
if (payment.getAmount() > 10000) {
if (payment.getUserLevel().equals("VIP")) {
payment.setStatus("APPROVED");
} else {
payment.setStatus("NEED_REVIEW");
}
} else {
payment.setStatus("APPROVED");
}
} else if (payment.getStatus().equals("APPROVED") && action.equals("pay")) {
// 又是一堆 if-else...
} else if (...) {
// 无限嵌套...
}
}这种代码的问题在于:状态流转规则散落在各处,没有人能说清楚系统到底有多少种状态、多少种流转路径。
而有了状态机,业务规则变成了"契约":
状态A + 事件X → 状态B(必须满足条件C)新人接手项目,看一眼状态流转图就能理解业务;产品经理提需求,先画状态图再讨论;出了 bug,对照状态机排查一目了然。
2. 防止"非法状态转换"
在支付系统中,状态的正确性直接关系到钱。想象一下这些恐怖场景:
- 一笔已经退款成功的交易,又被标记为支付成功(用户白嫖)
- 一笔处理中的交易,直接跳到已完成(跳过了风控检查)
- 一笔已取消的订单,又被重新激活(幽灵订单)
状态机通过白名单机制杜绝这些问题:只有明确定义的流转路径才是合法的,其他一律拒绝。
// 状态机会直接拒绝非法操作
stateMachine.fire(DepositEvent.DEPOSIT_SUCCESS);
// IllegalStateException: 状态[REFUND_SUCCESS]不支持事件[DEPOSIT_SUCCESS]3. 天然的审计追踪能力
金融系统对审计的要求非常高。有了状态机,每一次状态变更都是一个明确的"事件":
2024-01-15 10:23:45 | TXN_001 | WAIT_VERIFY → VERIFIED | EVENT: VERIFY_PASS | OPERATOR: SYSTEM
2024-01-15 10:23:46 | TXN_001 | VERIFIED → PENDING | EVENT: DEPOSIT_PENDING | OPERATOR: SYSTEM
2024-01-15 10:25:12 | TXN_001 | PENDING → REFUND_PROCESSING | EVENT: DEPOSIT_FAILED | OPERATOR: SYSTEM
2024-01-15 14:30:00 | TXN_001 | REFUND_PROCESSING → REFUND_SUCCESS | EVENT: REFUND_SUCCESS | OPERATOR: SYSTEM完整的状态流转链路,出了问题可以精确定位到是哪个环节、什么时间、由谁触发的。
4. 支持复杂的业务编排
实际的支付系统远比想象的复杂:
- 并行状态:一笔交易可能同时处于"支付处理中"和"风控审核中"
- 嵌套状态:退款流程本身也是一个子状态机
- 超时处理:处理中状态超过 30 分钟自动触发人工审核
- 补偿机制:某个步骤失败后自动触发回滚
这些复杂场景,用 if-else 写出来会是什么样子?我不敢想。而状态机天然支持这些高级特性。
5. 代码即文档
一个设计良好的状态机,本身就是最好的业务文档:
// 看这段代码,不需要任何注释,你就知道业务规则是什么
.transition()
.from(DepositStatus.PENDING)
.to(DepositStatus.REFUND_PROCESSING)
.on(DepositEvent.DEPOSIT_FAILED)
.guard(ctx -> ctx.getTransaction().getRetryCount() >= 3) // 重试3次才退款
.action(ctx -> refundService.initiateRefund(ctx.getPayload()))状态机在支付系统中的典型应用
支付系统可以说是状态机的"最佳实践场",几乎每个核心流程都离不开它:
在我们的入金场景中,一笔交易从收到客户的转账,到最终入账成功或退款完成,要经历多个状态的流转。每个状态代表着交易在某个特定阶段,每次状态变更都意味着业务的推进。
好了,理论知识铺垫完毕。接下来,让我们看看这个真实的入金状态流转图,然后用五种不同的方式来实现它。
问题场景
先看一下我们入金系统的状态流转图:
状态说明:
| 状态缩写 | 全称 | 说明 | 处理方式 |
|---|---|---|---|
| WV | Wait_Verify | 等待验证 | 系统自动 |
| V | Verified | 已验证 | 系统自动 |
| P | Pending | 处理中 | 系统自动 |
| S | Success | 成功 | 系统自动 |
| MC | Manual_Confirm | 人工确认 | 人工处理 |
| RP | Refund_Processing | 退款处理中 | 系统自动 |
| RS | Refund_Success | 退款成功 | 系统自动 |
| RF | Refund_Failed | 退款失败 | 人工处理 |
| MF | Manual_Failed | 人工确认失败 | 系统自动 |
| RT | Return_Ticket | 退票 | 人工处理 |
看到这张图,是不是有种想转行的冲动?别慌,我们一步步来拆解。
方案一:Switch/If-Else 硬刚(适合勇士)
这是最原始、最直接、最容易被后人骂的方式。但作为入门,还是要了解一下。
状态与事件定义
/**
* 入金交易状态枚举
*/
public enum DepositStatus {
WAIT_VERIFY("WV", "等待验证"),
VERIFIED("V", "已验证"),
PENDING("P", "处理中"),
SUCCESS("S", "成功"),
MANUAL_CONFIRM("MC", "人工确认"),
REFUND_PROCESSING("RP", "退款处理中"),
REFUND_SUCCESS("RS", "退款成功"),
REFUND_FAILED("RF", "退款失败"),
MANUAL_FAILED("MF", "人工确认失败"),
RETURN_TICKET("RT", "退票");
private final String code;
private final String desc;
DepositStatus(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() { return code; }
public String getDesc() { return desc; }
}
/**
* 状态流转事件枚举
*/
public enum DepositEvent {
IBAN_NOT_FOUND("IBAN未找到"),
VERIFY_PASS("验证通过"),
VERIFY_FAIL("验证失败"),
DEPOSIT_PENDING("入金处理中"),
DEPOSIT_SUCCESS("入金成功"),
DEPOSIT_FAILED("入金失败"),
ACCOUNT_VALIDATE_FAIL("账户校验失败"),
MANUAL_CONFIRM_REFUND("人工确认退款"),
MANUAL_CONFIRM_SUCCESS("人工确认成功"),
MANUAL_CONFIRM_FAILED("人工确认失败"),
REFUND_SUCCESS("退款成功"),
REFUND_FAILED("退款失败"),
RECEIVE_RETURN_TICKET("收到退票通知"),
STILL_PENDING("仍在处理中");
private final String desc;
DepositEvent(String desc) {
this.desc = desc;
}
public String getDesc() { return desc; }
}Switch 实现
/**
* 状态机服务 - Switch版本
*
* 优点:简单直接,一眼能看懂
* 缺点:当状态和事件增多时,这个方法会膨胀到让你怀疑人生
*/
@Service
@Slf4j
public class DepositStateMachineSwitch {
public DepositStatus transition(DepositStatus currentStatus, DepositEvent event) {
log.info("状态流转: {} + {} -> ?", currentStatus, event);
switch (currentStatus) {
case WAIT_VERIFY:
return handleWaitVerify(event);
case VERIFIED:
return handleVerified(event);
case PENDING:
return handlePending(event);
case MANUAL_CONFIRM:
return handleManualConfirm(event);
case REFUND_PROCESSING:
return handleRefundProcessing(event);
case REFUND_FAILED:
return handleRefundFailed(event);
case REFUND_SUCCESS:
return handleRefundSuccess(event);
case RETURN_TICKET:
return handleReturnTicket(event);
case SUCCESS:
case MANUAL_FAILED:
// 终态,不再流转
throw new IllegalStateException("终态不允许继续流转: " + currentStatus);
default:
throw new IllegalArgumentException("未知状态: " + currentStatus);
}
}
private DepositStatus handleWaitVerify(DepositEvent event) {
switch (event) {
case VERIFY_PASS:
return DepositStatus.VERIFIED;
case VERIFY_FAIL:
return DepositStatus.MANUAL_CONFIRM;
default:
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.WAIT_VERIFY, event));
}
}
private DepositStatus handleVerified(DepositEvent event) {
switch (event) {
case DEPOSIT_PENDING:
return DepositStatus.PENDING;
case ACCOUNT_VALIDATE_FAIL:
return DepositStatus.REFUND_PROCESSING;
default:
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.VERIFIED, event));
}
}
private DepositStatus handlePending(DepositEvent event) {
switch (event) {
case STILL_PENDING:
return DepositStatus.PENDING; // 自循环
case DEPOSIT_SUCCESS:
return DepositStatus.SUCCESS;
case DEPOSIT_FAILED:
return DepositStatus.REFUND_PROCESSING;
default:
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.PENDING, event));
}
}
private DepositStatus handleManualConfirm(DepositEvent event) {
switch (event) {
case MANUAL_CONFIRM_REFUND:
return DepositStatus.REFUND_PROCESSING;
case MANUAL_CONFIRM_SUCCESS:
return DepositStatus.REFUND_SUCCESS;
case MANUAL_CONFIRM_FAILED:
return DepositStatus.MANUAL_FAILED;
default:
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.MANUAL_CONFIRM, event));
}
}
private DepositStatus handleRefundProcessing(DepositEvent event) {
switch (event) {
case REFUND_SUCCESS:
return DepositStatus.REFUND_SUCCESS;
case REFUND_FAILED:
return DepositStatus.REFUND_FAILED;
default:
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.REFUND_PROCESSING, event));
}
}
private DepositStatus handleRefundFailed(DepositEvent event) {
if (event == DepositEvent.MANUAL_CONFIRM_SUCCESS) {
return DepositStatus.REFUND_SUCCESS;
}
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.REFUND_FAILED, event));
}
private DepositStatus handleRefundSuccess(DepositEvent event) {
if (event == DepositEvent.RECEIVE_RETURN_TICKET) {
return DepositStatus.RETURN_TICKET;
}
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.REFUND_SUCCESS, event));
}
private DepositStatus handleReturnTicket(DepositEvent event) {
if (event == DepositEvent.MANUAL_CONFIRM_SUCCESS) {
return DepositStatus.REFUND_SUCCESS;
}
throw new IllegalStateException(
String.format("状态[%s]不支持事件[%s]", DepositStatus.RETURN_TICKET, event));
}
}点评: 这种写法就像你家的电线,刚装修完还能看,过两年再看就是一团乱麻。不过它胜在简单,适合状态少、改动少的场景。
方案二:状态模式(设计模式爱好者的最爱)
状态模式是 GoF 23 种设计模式之一,核心思想是把每个状态的行为封装到独立的类中。
类图设计
代码实现
/**
* 状态接口
*/
public interface DepositState {
/**
* 处理事件,返回新状态
*/
DepositState handle(DepositContext context, DepositEvent event);
/**
* 获取当前状态枚举
*/
DepositStatus getStatus();
/**
* 是否为终态
*/
default boolean isFinal() {
return false;
}
}
/**
* 上下文类 - 持有当前状态并管理状态流转
*/
@Slf4j
public class DepositContext {
private DepositState currentState;
private final DepositTransaction transaction;
private final List<StateChangeListener> listeners = new ArrayList<>();
public DepositContext(DepositTransaction transaction) {
this.transaction = transaction;
// 根据交易初始化状态
this.currentState = StateFactory.createState(transaction.getStatus());
}
public void fireEvent(DepositEvent event) {
if (currentState.isFinal()) {
throw new IllegalStateException("当前状态为终态,无法继续流转");
}
DepositStatus oldStatus = currentState.getStatus();
DepositState newState = currentState.handle(this, event);
if (newState != currentState) {
this.currentState = newState;
this.transaction.setStatus(newState.getStatus());
log.info("状态流转: {} --[{}]--> {}", oldStatus, event, newState.getStatus());
// 通知监听器
listeners.forEach(l -> l.onStateChange(oldStatus, newState.getStatus(), event));
}
}
public DepositStatus getCurrentStatus() {
return currentState.getStatus();
}
public DepositTransaction getTransaction() {
return transaction;
}
public void addListener(StateChangeListener listener) {
listeners.add(listener);
}
}
/**
* 等待验证状态
*/
public class WaitVerifyState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
switch (event) {
case VERIFY_PASS:
return new VerifiedState();
case VERIFY_FAIL:
return new ManualConfirmState();
default:
throw new IllegalStateException("WaitVerify状态不支持事件: " + event);
}
}
@Override
public DepositStatus getStatus() {
return DepositStatus.WAIT_VERIFY;
}
}
/**
* 已验证状态
*/
public class VerifiedState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
switch (event) {
case DEPOSIT_PENDING:
return new PendingState();
case ACCOUNT_VALIDATE_FAIL:
return new RefundProcessingState();
default:
throw new IllegalStateException("Verified状态不支持事件: " + event);
}
}
@Override
public DepositStatus getStatus() {
return DepositStatus.VERIFIED;
}
}
/**
* 处理中状态
*/
public class PendingState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
switch (event) {
case STILL_PENDING:
return this; // 自循环,返回自身
case DEPOSIT_SUCCESS:
return new SuccessState();
case DEPOSIT_FAILED:
return new RefundProcessingState();
default:
throw new IllegalStateException("Pending状态不支持事件: " + event);
}
}
@Override
public DepositStatus getStatus() {
return DepositStatus.PENDING;
}
}
/**
* 人工确认状态
*/
public class ManualConfirmState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
switch (event) {
case MANUAL_CONFIRM_REFUND:
return new RefundProcessingState();
case MANUAL_CONFIRM_SUCCESS:
return new RefundSuccessState();
case MANUAL_CONFIRM_FAILED:
return new ManualFailedState();
default:
throw new IllegalStateException("ManualConfirm状态不支持事件: " + event);
}
}
@Override
public DepositStatus getStatus() {
return DepositStatus.MANUAL_CONFIRM;
}
}
/**
* 退款处理中状态
*/
public class RefundProcessingState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
switch (event) {
case REFUND_SUCCESS:
return new RefundSuccessState();
case REFUND_FAILED:
return new RefundFailedState();
default:
throw new IllegalStateException("RefundProcessing状态不支持事件: " + event);
}
}
@Override
public DepositStatus getStatus() {
return DepositStatus.REFUND_PROCESSING;
}
}
/**
* 退款失败状态 - 需要人工处理
*/
public class RefundFailedState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
if (event == DepositEvent.MANUAL_CONFIRM_SUCCESS) {
return new RefundSuccessState();
}
throw new IllegalStateException("RefundFailed状态不支持事件: " + event);
}
@Override
public DepositStatus getStatus() {
return DepositStatus.REFUND_FAILED;
}
}
/**
* 退款成功状态
*/
public class RefundSuccessState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
if (event == DepositEvent.RECEIVE_RETURN_TICKET) {
return new ReturnTicketState();
}
throw new IllegalStateException("RefundSuccess状态不支持事件: " + event);
}
@Override
public DepositStatus getStatus() {
return DepositStatus.REFUND_SUCCESS;
}
@Override
public boolean isFinal() {
// 这里有点特殊,RS可能收到退票通知,所以不是严格终态
return false;
}
}
/**
* 退票状态 - 需要人工处理
*/
public class ReturnTicketState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
if (event == DepositEvent.MANUAL_CONFIRM_SUCCESS) {
return new RefundSuccessState();
}
throw new IllegalStateException("ReturnTicket状态不支持事件: " + event);
}
@Override
public DepositStatus getStatus() {
return DepositStatus.RETURN_TICKET;
}
}
/**
* 成功状态 - 终态
*/
public class SuccessState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
throw new IllegalStateException("Success是终态,不支持任何事件");
}
@Override
public DepositStatus getStatus() {
return DepositStatus.SUCCESS;
}
@Override
public boolean isFinal() {
return true;
}
}
/**
* 人工确认失败状态 - 终态
*/
public class ManualFailedState implements DepositState {
@Override
public DepositState handle(DepositContext context, DepositEvent event) {
throw new IllegalStateException("ManualFailed是终态,不支持任何事件");
}
@Override
public DepositStatus getStatus() {
return DepositStatus.MANUAL_FAILED;
}
@Override
public boolean isFinal() {
return true;
}
}
/**
* 状态工厂
*/
public class StateFactory {
private static final Map<DepositStatus, Supplier<DepositState>> STATE_MAP = new EnumMap<>(DepositStatus.class);
static {
STATE_MAP.put(DepositStatus.WAIT_VERIFY, WaitVerifyState::new);
STATE_MAP.put(DepositStatus.VERIFIED, VerifiedState::new);
STATE_MAP.put(DepositStatus.PENDING, PendingState::new);
STATE_MAP.put(DepositStatus.SUCCESS, SuccessState::new);
STATE_MAP.put(DepositStatus.MANUAL_CONFIRM, ManualConfirmState::new);
STATE_MAP.put(DepositStatus.REFUND_PROCESSING, RefundProcessingState::new);
STATE_MAP.put(DepositStatus.REFUND_SUCCESS, RefundSuccessState::new);
STATE_MAP.put(DepositStatus.REFUND_FAILED, RefundFailedState::new);
STATE_MAP.put(DepositStatus.MANUAL_FAILED, ManualFailedState::new);
STATE_MAP.put(DepositStatus.RETURN_TICKET, ReturnTicketState::new);
}
public static DepositState createState(DepositStatus status) {
Supplier<DepositState> supplier = STATE_MAP.get(status);
if (supplier == null) {
throw new IllegalArgumentException("未知状态: " + status);
}
return supplier.get();
}
}点评: 状态模式符合开闭原则,新增状态只需要新增类。但代码量确实大,10 个状态就要写 10 个类,这还没算上接口和工厂。适合状态行为复杂、需要独立测试的场景。
方案三:基于状态枚举的流转表(推荐)
这是我个人比较喜欢的方案,把状态流转规则用数据结构来表达,代码量小,可读性高。
核心思想
用一个 Map<当前状态, Map<事件, 目标状态>> 来定义所有合法的状态流转路径。
代码实现
/**
* 状态流转配置 - 基于枚举的声明式配置
*
* 这种方式的好处是:状态流转规则一目了然,像看配置文件一样
*/
@Component
public class DepositStateTransitionTable {
/**
* 状态流转表
* 结构: 当前状态 -> (事件 -> 目标状态)
*/
private final Map<DepositStatus, Map<DepositEvent, DepositStatus>> transitionTable;
public DepositStateTransitionTable() {
this.transitionTable = buildTransitionTable();
}
private Map<DepositStatus, Map<DepositEvent, DepositStatus>> buildTransitionTable() {
Map<DepositStatus, Map<DepositEvent, DepositStatus>> table = new EnumMap<>(DepositStatus.class);
// WV(等待验证) 的流转规则
table.put(DepositStatus.WAIT_VERIFY, Map.of(
DepositEvent.VERIFY_PASS, DepositStatus.VERIFIED,
DepositEvent.VERIFY_FAIL, DepositStatus.MANUAL_CONFIRM
));
// V(已验证) 的流转规则
table.put(DepositStatus.VERIFIED, Map.of(
DepositEvent.DEPOSIT_PENDING, DepositStatus.PENDING,
DepositEvent.ACCOUNT_VALIDATE_FAIL, DepositStatus.REFUND_PROCESSING
));
// P(处理中) 的流转规则
table.put(DepositStatus.PENDING, Map.of(
DepositEvent.STILL_PENDING, DepositStatus.PENDING,
DepositEvent.DEPOSIT_SUCCESS, DepositStatus.SUCCESS,
DepositEvent.DEPOSIT_FAILED, DepositStatus.REFUND_PROCESSING
));
// MC(人工确认) 的流转规则
table.put(DepositStatus.MANUAL_CONFIRM, Map.of(
DepositEvent.MANUAL_CONFIRM_REFUND, DepositStatus.REFUND_PROCESSING,
DepositEvent.MANUAL_CONFIRM_SUCCESS, DepositStatus.REFUND_SUCCESS,
DepositEvent.MANUAL_CONFIRM_FAILED, DepositStatus.MANUAL_FAILED
));
// RP(退款处理中) 的流转规则
table.put(DepositStatus.REFUND_PROCESSING, Map.of(
DepositEvent.REFUND_SUCCESS, DepositStatus.REFUND_SUCCESS,
DepositEvent.REFUND_FAILED, DepositStatus.REFUND_FAILED
));
// RF(退款失败) 的流转规则 - 需要人工处理
table.put(DepositStatus.REFUND_FAILED, Map.of(
DepositEvent.MANUAL_CONFIRM_SUCCESS, DepositStatus.REFUND_SUCCESS
));
// RS(退款成功) 的流转规则
table.put(DepositStatus.REFUND_SUCCESS, Map.of(
DepositEvent.RECEIVE_RETURN_TICKET, DepositStatus.RETURN_TICKET
));
// RT(退票) 的流转规则 - 需要人工处理
table.put(DepositStatus.RETURN_TICKET, Map.of(
DepositEvent.MANUAL_CONFIRM_SUCCESS, DepositStatus.REFUND_SUCCESS
));
// 终态没有流转规则
table.put(DepositStatus.SUCCESS, Map.of());
table.put(DepositStatus.MANUAL_FAILED, Map.of());
return Collections.unmodifiableMap(table);
}
/**
* 执行状态流转
*/
public DepositStatus transition(DepositStatus current, DepositEvent event) {
Map<DepositEvent, DepositStatus> transitions = transitionTable.get(current);
if (transitions == null || transitions.isEmpty()) {
throw new IllegalStateException(
String.format("状态[%s]是终态,无法继续流转", current));
}
DepositStatus target = transitions.get(event);
if (target == null) {
throw new IllegalStateException(
String.format("非法的状态流转: %s + %s", current, event));
}
return target;
}
/**
* 检查流转是否合法
*/
public boolean canTransition(DepositStatus current, DepositEvent event) {
Map<DepositEvent, DepositStatus> transitions = transitionTable.get(current);
return transitions != null && transitions.containsKey(event);
}
/**
* 获取某状态下所有可能的事件
*/
public Set<DepositEvent> getAvailableEvents(DepositStatus current) {
Map<DepositEvent, DepositStatus> transitions = transitionTable.get(current);
return transitions != null ? transitions.keySet() : Collections.emptySet();
}
/**
* 判断是否为终态
*/
public boolean isFinalState(DepositStatus status) {
Map<DepositEvent, DepositStatus> transitions = transitionTable.get(status);
return transitions == null || transitions.isEmpty();
}
}
/**
* 状态机服务 - 基于流转表
*/
@Service
@Slf4j
public class DepositStateMachineService {
private final DepositStateTransitionTable transitionTable;
private final DepositTransactionRepository repository;
private final ApplicationEventPublisher eventPublisher;
public DepositStateMachineService(DepositStateTransitionTable transitionTable,
DepositTransactionRepository repository,
ApplicationEventPublisher eventPublisher) {
this.transitionTable = transitionTable;
this.repository = repository;
this.eventPublisher = eventPublisher;
}
/**
* 触发状态流转
*/
@Transactional
public DepositTransaction fireEvent(String transactionId, DepositEvent event) {
DepositTransaction transaction = repository.findById(transactionId)
.orElseThrow(() -> new IllegalArgumentException("交易不存在: " + transactionId));
DepositStatus currentStatus = transaction.getStatus();
// 执行流转
DepositStatus newStatus = transitionTable.transition(currentStatus, event);
// 更新交易状态
transaction.setStatus(newStatus);
transaction.setUpdatedAt(LocalDateTime.now());
transaction = repository.save(transaction);
log.info("状态流转成功: {} --[{}]--> {}, transactionId={}",
currentStatus, event, newStatus, transactionId);
// 发布状态变更事件
eventPublisher.publishEvent(new DepositStateChangedEvent(
this, transactionId, currentStatus, newStatus, event));
return transaction;
}
/**
* 批量查询可操作的事件
*/
public Map<String, Set<DepositEvent>> getAvailableEvents(List<String> transactionIds) {
return repository.findAllById(transactionIds).stream()
.collect(Collectors.toMap(
DepositTransaction::getId,
t -> transitionTable.getAvailableEvents(t.getStatus())
));
}
}点评: 这种方式把"状态流转规则"和"流转逻辑"分离,规则以数据的形式呈现,非常直观。扩展新状态只需要在表里加一行配置。强烈推荐中小型项目使用。
方案四:Spring State Machine(官方出品)
如果你是 Spring 生态的忠实粉丝,那 Spring State Machine 是官方钦定的选择。
Maven 依赖
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>3.2.0</version>
</dependency>状态机配置
/**
* Spring State Machine 配置类
*/
@Configuration
@EnableStateMachine
@Slf4j
public class DepositStateMachineConfig
extends EnumStateMachineConfigurerAdapter<DepositStatus, DepositEvent> {
@Override
public void configure(StateMachineStateConfigurer<DepositStatus, DepositEvent> states)
throws Exception {
states
.withStates()
.initial(DepositStatus.WAIT_VERIFY)
.end(DepositStatus.SUCCESS)
.end(DepositStatus.MANUAL_FAILED)
.states(EnumSet.allOf(DepositStatus.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<DepositStatus, DepositEvent> transitions)
throws Exception {
transitions
// 初始状态流转
.withExternal()
.source(DepositStatus.WAIT_VERIFY)
.target(DepositStatus.VERIFIED)
.event(DepositEvent.VERIFY_PASS)
.and()
.withExternal()
.source(DepositStatus.WAIT_VERIFY)
.target(DepositStatus.MANUAL_CONFIRM)
.event(DepositEvent.VERIFY_FAIL)
.and()
// Verified 状态流转
.withExternal()
.source(DepositStatus.VERIFIED)
.target(DepositStatus.PENDING)
.event(DepositEvent.DEPOSIT_PENDING)
.and()
.withExternal()
.source(DepositStatus.VERIFIED)
.target(DepositStatus.REFUND_PROCESSING)
.event(DepositEvent.ACCOUNT_VALIDATE_FAIL)
.and()
// Pending 状态流转
.withInternal()
.source(DepositStatus.PENDING)
.event(DepositEvent.STILL_PENDING)
.action(ctx -> log.info("仍在处理中..."))
.and()
.withExternal()
.source(DepositStatus.PENDING)
.target(DepositStatus.SUCCESS)
.event(DepositEvent.DEPOSIT_SUCCESS)
.and()
.withExternal()
.source(DepositStatus.PENDING)
.target(DepositStatus.REFUND_PROCESSING)
.event(DepositEvent.DEPOSIT_FAILED)
.and()
// Manual Confirm 状态流转
.withExternal()
.source(DepositStatus.MANUAL_CONFIRM)
.target(DepositStatus.REFUND_PROCESSING)
.event(DepositEvent.MANUAL_CONFIRM_REFUND)
.and()
.withExternal()
.source(DepositStatus.MANUAL_CONFIRM)
.target(DepositStatus.REFUND_SUCCESS)
.event(DepositEvent.MANUAL_CONFIRM_SUCCESS)
.and()
.withExternal()
.source(DepositStatus.MANUAL_CONFIRM)
.target(DepositStatus.MANUAL_FAILED)
.event(DepositEvent.MANUAL_CONFIRM_FAILED)
.and()
// Refund Processing 状态流转
.withExternal()
.source(DepositStatus.REFUND_PROCESSING)
.target(DepositStatus.REFUND_SUCCESS)
.event(DepositEvent.REFUND_SUCCESS)
.and()
.withExternal()
.source(DepositStatus.REFUND_PROCESSING)
.target(DepositStatus.REFUND_FAILED)
.event(DepositEvent.REFUND_FAILED)
.and()
// Refund Failed 状态流转(人工处理)
.withExternal()
.source(DepositStatus.REFUND_FAILED)
.target(DepositStatus.REFUND_SUCCESS)
.event(DepositEvent.MANUAL_CONFIRM_SUCCESS)
.and()
// Refund Success 状态流转
.withExternal()
.source(DepositStatus.REFUND_SUCCESS)
.target(DepositStatus.RETURN_TICKET)
.event(DepositEvent.RECEIVE_RETURN_TICKET)
.and()
// Return Ticket 状态流转(人工处理)
.withExternal()
.source(DepositStatus.RETURN_TICKET)
.target(DepositStatus.REFUND_SUCCESS)
.event(DepositEvent.MANUAL_CONFIRM_SUCCESS);
}
@Override
public void configure(StateMachineConfigurationConfigurer<DepositStatus, DepositEvent> config)
throws Exception {
config
.withConfiguration()
.autoStartup(true)
.listener(new StateMachineListenerAdapter<>() {
@Override
public void stateChanged(State<DepositStatus, DepositEvent> from,
State<DepositStatus, DepositEvent> to) {
log.info("状态变更: {} -> {}",
from != null ? from.getId() : "INIT",
to.getId());
}
@Override
public void eventNotAccepted(Message<DepositEvent> event) {
log.warn("事件被拒绝: {}", event.getPayload());
}
});
}
}
/**
* 状态流转 Action 配置
*/
@Configuration
public class DepositStateMachineActions {
@Bean
public Action<DepositStatus, DepositEvent> depositSuccessAction() {
return context -> {
DepositTransaction transaction = context.getExtendedState()
.get("transaction", DepositTransaction.class);
// 入金成功的业务逻辑
log.info("入金成功,交易ID: {}", transaction.getId());
};
}
@Bean
public Action<DepositStatus, DepositEvent> refundAction() {
return context -> {
DepositTransaction transaction = context.getExtendedState()
.get("transaction", DepositTransaction.class);
// 发起退款的业务逻辑
log.info("发起退款,交易ID: {}", transaction.getId());
};
}
@Bean
public Guard<DepositStatus, DepositEvent> verifyGuard() {
return context -> {
DepositTransaction transaction = context.getExtendedState()
.get("transaction", DepositTransaction.class);
// 验证条件
return transaction != null && transaction.getAmount() != null;
};
}
}
/**
* 状态机服务 - 封装 Spring State Machine 的使用
*/
@Service
@Slf4j
public class SpringStateMachineService {
private final StateMachineFactory<DepositStatus, DepositEvent> stateMachineFactory;
private final StateMachinePersister<DepositStatus, DepositEvent, String> persister;
private final DepositTransactionRepository repository;
public SpringStateMachineService(
StateMachineFactory<DepositStatus, DepositEvent> stateMachineFactory,
StateMachinePersister<DepositStatus, DepositEvent, String> persister,
DepositTransactionRepository repository) {
this.stateMachineFactory = stateMachineFactory;
this.persister = persister;
this.repository = repository;
}
/**
* 触发事件
*/
@Transactional
public boolean fireEvent(String transactionId, DepositEvent event) {
DepositTransaction transaction = repository.findById(transactionId)
.orElseThrow(() -> new IllegalArgumentException("交易不存在"));
// 获取或创建状态机实例
StateMachine<DepositStatus, DepositEvent> stateMachine =
stateMachineFactory.getStateMachine(transactionId);
try {
// 恢复状态机状态
persister.restore(stateMachine, transactionId);
// 设置上下文
stateMachine.getExtendedState().getVariables().put("transaction", transaction);
// 发送事件
boolean accepted = stateMachine.sendEvent(Mono.just(
MessageBuilder.withPayload(event).build()
)).blockLast().getResultType() == ResultType.ACCEPTED;
if (accepted) {
// 持久化状态
persister.persist(stateMachine, transactionId);
// 更新数据库
transaction.setStatus(stateMachine.getState().getId());
repository.save(transaction);
}
return accepted;
} catch (Exception e) {
log.error("状态机执行异常", e);
throw new RuntimeException("状态流转失败", e);
}
}
}
/**
* 状态机持久化配置
*/
@Configuration
public class StateMachinePersistConfig {
@Bean
public StateMachinePersister<DepositStatus, DepositEvent, String> persister(
StateMachineRuntimePersister<DepositStatus, DepositEvent, String> runtimePersister) {
return new DefaultStateMachinePersister<>(runtimePersister);
}
@Bean
public StateMachineRuntimePersister<DepositStatus, DepositEvent, String> runtimePersister(
JpaStateMachineRepository jpaRepository) {
return new JpaPersistingStateMachineInterceptor<>(jpaRepository);
}
}点评: Spring State Machine 功能强大,支持分布式、持久化、分层状态机等高级特性。但配置繁琐,学习成本高,而且在高并发场景下性能是个问题(状态机实例需要加锁)。适合对 Spring 生态有执念且状态流转逻辑复杂的项目。
方案五:自研轻量级状态机框架(架构师的自我修养)
如果你觉得 Spring State Machine 太重,又觉得简单的流转表不够灵活,那就自己撸一个吧。
设计目标
- 声明式配置:用流式 API 定义状态和流转
- 支持 Guard(守卫条件):流转前的条件检查
- 支持 Action(动作):流转时执行的业务逻辑
- 支持监听器:状态变更通知
- 线程安全:支持并发场景
- 轻量级:零外部依赖
架构设计
核心代码
/**
* 流转上下文
*/
@Data
@Builder
public class TransitionContext<S, E> {
private final S source;
private final S target;
private final E event;
private final Object payload;
private final Map<String, Object> variables;
@SuppressWarnings("unchecked")
public <T> T getPayload() {
return (T) payload;
}
public <T> T getVariable(String key, Class<T> type) {
return type.cast(variables.get(key));
}
}
/**
* 状态流转定义
*/
@Data
@Builder
public class Transition<S, E> {
private final S source;
private final S target;
private final E event;
private final Predicate<TransitionContext<S, E>> guard;
private final Consumer<TransitionContext<S, E>> action;
/**
* 执行流转
*/
public boolean execute(TransitionContext<S, E> context) {
// 检查守卫条件
if (guard != null && !guard.test(context)) {
return false;
}
// 执行动作
if (action != null) {
action.accept(context);
}
return true;
}
}
/**
* 状态变更监听器
*/
@FunctionalInterface
public interface StateChangeListener<S, E> {
void onStateChanged(S from, S to, E event, Object payload);
}
/**
* 轻量级状态机
*/
@Slf4j
public class LiteStateMachine<S, E> {
private volatile S currentState;
private final Map<S, Map<E, Transition<S, E>>> transitionTable;
private final Set<S> finalStates;
private final List<StateChangeListener<S, E>> listeners;
private final Map<String, Object> variables;
private final ReentrantLock lock = new ReentrantLock();
private LiteStateMachine(Builder<S, E> builder) {
this.currentState = builder.initialState;
this.transitionTable = builder.transitionTable;
this.finalStates = builder.finalStates;
this.listeners = new CopyOnWriteArrayList<>(builder.listeners);
this.variables = new ConcurrentHashMap<>(builder.variables);
}
/**
* 触发事件
*/
public boolean fire(E event, Object payload) {
lock.lock();
try {
if (isFinalState()) {
log.warn("当前状态[{}]是终态,无法触发事件[{}]", currentState, event);
return false;
}
Map<E, Transition<S, E>> transitions = transitionTable.get(currentState);
if (transitions == null) {
log.warn("状态[{}]没有配置任何流转规则", currentState);
return false;
}
Transition<S, E> transition = transitions.get(event);
if (transition == null) {
log.warn("状态[{}]不支持事件[{}]", currentState, event);
return false;
}
TransitionContext<S, E> context = TransitionContext.<S, E>builder()
.source(currentState)
.target(transition.getTarget())
.event(event)
.payload(payload)
.variables(new HashMap<>(variables))
.build();
// 执行流转
if (!transition.execute(context)) {
log.info("流转被Guard拦截: {} --[{}]--> {}", currentState, event, transition.getTarget());
return false;
}
S oldState = currentState;
currentState = transition.getTarget();
log.info("状态流转成功: {} --[{}]--> {}", oldState, event, currentState);
// 通知监听器
listeners.forEach(l -> {
try {
l.onStateChanged(oldState, currentState, event, payload);
} catch (Exception e) {
log.error("监听器执行异常", e);
}
});
return true;
} finally {
lock.unlock();
}
}
public boolean fire(E event) {
return fire(event, null);
}
public S getCurrentState() {
return currentState;
}
public boolean canFire(E event) {
Map<E, Transition<S, E>> transitions = transitionTable.get(currentState);
return transitions != null && transitions.containsKey(event);
}
public Set<E> getAvailableEvents() {
Map<E, Transition<S, E>> transitions = transitionTable.get(currentState);
return transitions != null ? transitions.keySet() : Collections.emptySet();
}
public boolean isFinalState() {
return finalStates.contains(currentState);
}
public void setVariable(String key, Object value) {
variables.put(key, value);
}
public void addListener(StateChangeListener<S, E> listener) {
listeners.add(listener);
}
/**
* 创建构建器
*/
public static <S, E> Builder<S, E> builder() {
return new Builder<>();
}
/**
* 状态机构建器
*/
public static class Builder<S, E> {
private S initialState;
private final Map<S, Map<E, Transition<S, E>>> transitionTable = new HashMap<>();
private final Set<S> finalStates = new HashSet<>();
private final List<StateChangeListener<S, E>> listeners = new ArrayList<>();
private final Map<String, Object> variables = new HashMap<>();
public Builder<S, E> initialState(S state) {
this.initialState = state;
return this;
}
public Builder<S, E> finalStates(S... states) {
this.finalStates.addAll(Arrays.asList(states));
return this;
}
public TransitionBuilder transition() {
return new TransitionBuilder();
}
public Builder<S, E> listener(StateChangeListener<S, E> listener) {
this.listeners.add(listener);
return this;
}
public Builder<S, E> variable(String key, Object value) {
this.variables.put(key, value);
return this;
}
public LiteStateMachine<S, E> build() {
Objects.requireNonNull(initialState, "初始状态不能为空");
return new LiteStateMachine<>(this);
}
/**
* 流转构建器
*/
public class TransitionBuilder {
private S source;
private S target;
private E event;
private Predicate<TransitionContext<S, E>> guard;
private Consumer<TransitionContext<S, E>> action;
public TransitionBuilder from(S source) {
this.source = source;
return this;
}
public TransitionBuilder to(S target) {
this.target = target;
return this;
}
public TransitionBuilder on(E event) {
this.event = event;
return this;
}
public TransitionBuilder guard(Predicate<TransitionContext<S, E>> guard) {
this.guard = guard;
return this;
}
public TransitionBuilder action(Consumer<TransitionContext<S, E>> action) {
this.action = action;
return this;
}
public Builder<S, E> and() {
Transition<S, E> transition = Transition.<S, E>builder()
.source(source)
.target(target)
.event(event)
.guard(guard)
.action(action)
.build();
transitionTable
.computeIfAbsent(source, k -> new HashMap<>())
.put(event, transition);
return Builder.this;
}
}
}
}使用示例
/**
* 入金状态机工厂
*/
@Component
@Slf4j
public class DepositStateMachineFactory {
private final RefundService refundService;
private final NotificationService notificationService;
public DepositStateMachineFactory(RefundService refundService,
NotificationService notificationService) {
this.refundService = refundService;
this.notificationService = notificationService;
}
/**
* 创建入金状态机实例
*/
public LiteStateMachine<DepositStatus, DepositEvent> create(DepositTransaction transaction) {
return LiteStateMachine.<DepositStatus, DepositEvent>builder()
// 根据交易当前状态初始化
.initialState(transaction.getStatus())
// 定义终态
.finalStates(DepositStatus.SUCCESS, DepositStatus.MANUAL_FAILED)
// 存储交易信息到上下文
.variable("transaction", transaction)
// WV -> V: 验证通过
.transition()
.from(DepositStatus.WAIT_VERIFY)
.to(DepositStatus.VERIFIED)
.on(DepositEvent.VERIFY_PASS)
.guard(ctx -> {
// 检查交易金额是否合法
DepositTransaction tx = ctx.getVariable("transaction", DepositTransaction.class);
return tx.getAmount() != null && tx.getAmount().compareTo(BigDecimal.ZERO) > 0;
})
.and()
// WV -> MC: 验证失败
.transition()
.from(DepositStatus.WAIT_VERIFY)
.to(DepositStatus.MANUAL_CONFIRM)
.on(DepositEvent.VERIFY_FAIL)
.action(ctx -> {
// 发送人工确认通知
notificationService.sendManualConfirmNotify(ctx.getPayload());
})
.and()
// V -> P: 入金处理中
.transition()
.from(DepositStatus.VERIFIED)
.to(DepositStatus.PENDING)
.on(DepositEvent.DEPOSIT_PENDING)
.and()
// V -> RP: 账户验证失败
.transition()
.from(DepositStatus.VERIFIED)
.to(DepositStatus.REFUND_PROCESSING)
.on(DepositEvent.ACCOUNT_VALIDATE_FAIL)
.action(ctx -> refundService.initiateRefund(ctx.getPayload()))
.and()
// P -> P: 仍在处理中(自循环)
.transition()
.from(DepositStatus.PENDING)
.to(DepositStatus.PENDING)
.on(DepositEvent.STILL_PENDING)
.and()
// P -> S: 入金成功
.transition()
.from(DepositStatus.PENDING)
.to(DepositStatus.SUCCESS)
.on(DepositEvent.DEPOSIT_SUCCESS)
.action(ctx -> {
log.info("入金成功,更新账户余额");
// 更新账户余额等业务逻辑
})
.and()
// P -> RP: 入金失败
.transition()
.from(DepositStatus.PENDING)
.to(DepositStatus.REFUND_PROCESSING)
.on(DepositEvent.DEPOSIT_FAILED)
.action(ctx -> refundService.initiateRefund(ctx.getPayload()))
.and()
// MC -> RP: 人工确认退款
.transition()
.from(DepositStatus.MANUAL_CONFIRM)
.to(DepositStatus.REFUND_PROCESSING)
.on(DepositEvent.MANUAL_CONFIRM_REFUND)
.action(ctx -> refundService.initiateRefund(ctx.getPayload()))
.and()
// MC -> RS: 人工确认退款成功
.transition()
.from(DepositStatus.MANUAL_CONFIRM)
.to(DepositStatus.REFUND_SUCCESS)
.on(DepositEvent.MANUAL_CONFIRM_SUCCESS)
.and()
// MC -> MF: 人工确认失败
.transition()
.from(DepositStatus.MANUAL_CONFIRM)
.to(DepositStatus.MANUAL_FAILED)
.on(DepositEvent.MANUAL_CONFIRM_FAILED)
.and()
// RP -> RS: 退款成功
.transition()
.from(DepositStatus.REFUND_PROCESSING)
.to(DepositStatus.REFUND_SUCCESS)
.on(DepositEvent.REFUND_SUCCESS)
.and()
// RP -> RF: 退款失败
.transition()
.from(DepositStatus.REFUND_PROCESSING)
.to(DepositStatus.REFUND_FAILED)
.on(DepositEvent.REFUND_FAILED)
.action(ctx -> notificationService.sendManualConfirmNotify(ctx.getPayload()))
.and()
// RF -> RS: 人工确认退款成功
.transition()
.from(DepositStatus.REFUND_FAILED)
.to(DepositStatus.REFUND_SUCCESS)
.on(DepositEvent.MANUAL_CONFIRM_SUCCESS)
.and()
// RS -> RT: 收到退票通知
.transition()
.from(DepositStatus.REFUND_SUCCESS)
.to(DepositStatus.RETURN_TICKET)
.on(DepositEvent.RECEIVE_RETURN_TICKET)
.action(ctx -> notificationService.sendManualConfirmNotify(ctx.getPayload()))
.and()
// RT -> RS: 人工确认退款成功
.transition()
.from(DepositStatus.RETURN_TICKET)
.to(DepositStatus.REFUND_SUCCESS)
.on(DepositEvent.MANUAL_CONFIRM_SUCCESS)
.and()
// 添加状态变更监听器
.listener((from, to, event, payload) -> {
log.info("状态机状态变更: {} --[{}]--> {}", from, to, event);
// 可以在这里做审计日志、消息通知等
})
.build();
}
}
/**
* 使用示例
*/
@Service
@Slf4j
public class DepositService {
private final DepositStateMachineFactory stateMachineFactory;
private final DepositTransactionRepository repository;
@Transactional
public void processDeposit(String transactionId, DepositEvent event, Object payload) {
DepositTransaction transaction = repository.findById(transactionId)
.orElseThrow(() -> new IllegalArgumentException("交易不存在"));
// 创建状态机
LiteStateMachine<DepositStatus, DepositEvent> stateMachine =
stateMachineFactory.create(transaction);
// 触发事件
boolean success = stateMachine.fire(event, payload);
if (success) {
// 更新交易状态
transaction.setStatus(stateMachine.getCurrentState());
repository.save(transaction);
log.info("交易状态更新成功: {}", transaction);
} else {
log.warn("状态流转失败,交易ID: {}, 当前状态: {}, 事件: {}",
transactionId, transaction.getStatus(), event);
}
}
}点评: 自研方案可以完全按照业务需求定制,没有任何冗余功能。缺点是需要自己维护,出了 bug 只能自己扛。适合有一定技术积累、追求极致可控的团队。
方案对比
| 方案 | 复杂度 | 可扩展性 | 性能 | 学习成本 | 适用场景 |
|---|---|---|---|---|---|
| Switch/If-Else | ⭐ | ⭐ | ⭐⭐⭐⭐⭐ | ⭐ | 状态少于5个的简单场景 |
| 状态模式 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 状态行为复杂、需要独立测试 |
| 状态枚举流转表 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | 中小型项目,推荐首选 |
| Spring State Machine | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | Spring 生态、需要分布式支持 |
| 自研轻量级框架 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 追求极致可控、有技术积累 |
最佳实践建议
- 状态枚举一定要有:不管用哪种方案,状态和事件都应该用枚举定义,避免魔法字符串
- 流转规则要可视化:建议用 Mermaid 或者其他工具画出状态流转图,方便团队理解和评审
- 做好审计日志:每次状态变更都要记录,方便排查问题
- 考虑并发场景:多个线程同时触发同一笔交易的状态流转,需要加锁或者用乐观锁
- 幂等性很重要:同一个事件重复触发,结果应该一致
- 分离状态和业务逻辑:状态流转逻辑和业务处理逻辑要分开,职责清晰
总结
状态机看起来简单,写好却不容易。从最原始的 if-else 到 Spring State Machine,每种方案都有其适用场景。
我的建议是:
- 快速原型:用 Switch 或状态枚举表
- 长期维护的项目:用状态枚举表或自研轻量级框架
- 大型分布式系统:考虑 Spring State Machine 或者自研支持分布式的方案
记住,没有最好的方案,只有最合适的方案。就像写代码一样,不是炫技,而是解决问题。
如果你看到这里还没放弃,那恭喜你,你已经比大部分人更了解状态机了。现在,去把你项目里的 if-else 地狱重构一下吧!