1. 为什么需要状态模式?
1.1 日常开发中的痛点
传统if-else实现示例
java
public class Order {
private String state; // 状态变量
public void handleEvent(String event) {
if ("待支付".equals(state)) {
if ("支付".equals(event)) {
System.out.println("转为已支付状态");
state = "已支付";
// 支付后逻辑...
} else if ("取消".equals(event)) {
System.out.println("订单已取消");
state = "已取消";
// 取消后逻辑...
}
} else if ("已支付".equals(state)) {
if ("发货".equals(event)) {
System.out.println("转为已发货状态");
state = "已发货";
// 发货后逻辑...
}
// 更多条件分支...
}
// 更多状态判断...
}
}
三大核心问题:
- 维护困难:当新增"退款中"状态时,需要在所有方法中插入新的条件分支
- 代码臃肿:单个方法可能包含数百行状态判断(实际项目中常见)
- 风险扩散:修改某个状态的逻辑时可能意外影响其他状态
graph TD
A[handleEvent方法] --> B[判断待支付]
A --> C[判断已支付]
A --> D[判断已发货]
B --> E[处理支付]
B --> F[处理取消]
C --> G[处理发货]
C --> H[处理退款]
D --> I[处理完成]
classDef red fill:#ff9999;
class B,C,D red;
1.2 状态模式的价值
架构级解决方案
graph LR
A[事件触发] --> B[当前状态对象]
B --> C[执行对应行为]
C --> D[自动切换状态]
subgraph 状态集合
B
E[已支付状态]
F[已发货状态]
end
classDef blue fill:#99ccff;
class B,E,F blue;
核心优势对比表:
维度 | 传统方式 | 状态模式 |
---|---|---|
代码组织 | 条件分支嵌套 | 面向对象封装 |
新增状态 | 修改所有相关方法 | 新增状态类即可 |
状态转换 | 显式修改状态变量 | 自动触发转换 |
单元测试 | 需要覆盖所有分支 | 可单独测试每个状态 |
可读性 | 随着状态增加急剧下降 | 保持清晰的类结构 |
代码结构转变示例
java
// 状态模式实现
public class PaidState implements OrderState {
public void handleEvent(OrderContext context, String event) {
if ("发货".equals(event)) {
context.setState(new ShippedState());
// 发货业务逻辑...
} else if ("退款".equals(event)) {
context.setState(new RefundingState());
// 退款业务逻辑...
}
}
}
// 上下文类保持简洁
public class OrderContext {
private OrderState currentState;
public void handleEvent(String event) {
currentState.handleEvent(this, event);
}
}
价值总结:
- 开闭原则:新增状态只需扩展新类,无需修改现有代码
- 关注点分离:每个状态独立管理自己的行为
- 消除魔法字符串:用类型安全的类代替字符串状态判断
- 运行时状态切换:动态改变对象行为(设计模式核心特征)
通过将状态变为「活的对象」,让系统获得与生物相似的适应性------每个状态对象就像细胞一样自主响应环境变化。这正是面向对象设计的精髓所在。
2. 状态模式核心概念
2.1 模式结构详解
(1) 状态接口(State)
java
// 定义所有状态必须遵守的契约
public interface TrafficLightState {
// 处理状态行为(参数可根据场景调整)
void handle(TrafficLightContext context);
// 可选:定义状态标识方法
default String getStateName() {
return this.getClass().getSimpleName();
}
}
核心作用:统一所有具体状态的行为入口,相当于交通信号灯的"操作说明书"
(2) 具体状态类(Concrete States)
java
// 红灯状态实现
public class RedLight implements TrafficLightState {
@Override
public void handle(TrafficLightContext context) {
System.out.println("红灯亮起:禁止通行");
// 执行红灯相关逻辑
scheduleNextState(context);
}
private void scheduleNextState(TrafficLightContext context) {
// 3秒后切换绿灯
new Timer().schedule(new TimerTask() {
@Override
public void run() {
context.setState(new GreenLight());
}
}, 3000);
}
}
// 绿灯状态实现(同理可扩展黄灯)
关键特征:每个状态类都是独立的业务逻辑单元,如同交通信号灯的灯泡组件
(3) 上下文类(Context)
java
public class TrafficLightContext {
private TrafficLightState currentState;
// 初始化默认状态
public TrafficLightContext() {
this.currentState = new RedLight();
}
// 状态切换入口
public void setState(TrafficLightState state) {
System.out.println("状态变更:"
+ currentState.getStateName()
+ " → "
+ state.getStateName());
this.currentState = state;
// 自动触发新状态处理
this.currentState.handle(this);
}
// 客户端操作入口
public void request() {
currentState.handle(this);
}
}
核心职责:作为状态机的容器,像交通信号灯的控制箱一样管理当前状态
2.2 UML图示精解
classDiagram
class TrafficLightContext {
-currentState: TrafficLightState
+setState(TrafficLightState)
+request()
}
class TrafficLightState {
+handle(TrafficLightContext)
+getStateName() String
}
class RedLight {
+handle(TrafficLightContext)
}
class GreenLight {
+handle(TrafficLightContext)
}
class YellowLight {
+handle(TrafficLightContext)
}
TrafficLightContext --> TrafficLightState : 持有当前状态
TrafficLightState <|.. RedLight : 实现
TrafficLightState <|.. GreenLight : 实现
TrafficLightState <|.. YellowLight : 实现
图示关键点解析:
- 依赖方向:上下文类依赖状态接口(而非具体实现),符合依赖倒置原则
- 状态切换 :通过
setState()
方法实现状态转换(箭头未直接体现) - 闭环系统:状态对象可以反向操作上下文,形成完整的控制循环
2.3 运行流程图解
sequenceDiagram
participant Client
participant Context
participant State
Client->>Context: request()
Context->>State: handle(context)
State-->>Context: setState(newState)
Note over Context: 状态变更通知
Context->>newState: handle(context)
流程说明:
- 客户端触发上下文请求
- 当前状态处理业务逻辑
- 状态处理完成后主动切换新状态
- 新状态立即开始处理后续逻辑
设计精髓:每个状态既是当前行为的执行者,也是下一个状态的调度者,形成自动化的工作流。
3. 实战:电商订单系统
3.1 场景描述
订单状态完整流转图
stateDiagram-v2
[*] --> 待支付
待支付 --> 已支付 : 支付成功
待支付 --> 已取消 : 用户取消
已支付 --> 已发货 : 商家发货
已支付 --> 已取消 : 超时未发货
已发货 --> 已完成 : 用户确认收货
已发货 --> 退款中 : 发起退款
退款中 --> 已取消 : 退款成功
退款中 --> 已发货 : 取消退款
3.2 传统实现 vs 状态模式
传统实现代码示例
java
public class TraditionalOrder {
private String state = "待支付";
public void handleEvent(String event) {
if ("待支付".equals(state)) {
if ("支付".equals(event)) {
state = "已支付";
System.out.println("执行支付后操作:生成交易记录");
// 其他支付相关逻辑...
} else if ("取消".equals(event)) {
state = "已取消";
System.out.println("执行取消操作:释放库存");
// 其他取消相关逻辑...
}
} else if ("已支付".equals(state)) {
if ("发货".equals(event)) {
state = "已发货";
System.out.println("执行发货操作:生成物流单");
// 其他发货逻辑...
} else if ("取消".equals(event)) {
state = "已取消";
System.out.println("执行取消操作:发起退款");
// 其他退款逻辑...
}
}
// 更多else if分支...
}
}
状态模式实现
java
// 状态接口
public interface OrderState {
void handlePay(OrderContext context);
void handleCancel(OrderContext context);
void handleShip(OrderContext context);
void handleComplete(OrderContext context);
}
// 具体状态实现
public class UnpaidState implements OrderState {
@Override
public void handlePay(OrderContext context) {
System.out.println("执行支付操作");
// 支付相关业务逻辑...
context.setState(new PaidState());
}
@Override
public void handleCancel(OrderContext context) {
System.out.println("执行取消操作");
// 释放库存等操作...
context.setState(new CancelledState());
}
@Override
public void handleShip(OrderContext context) {
throw new IllegalStateException("待支付状态不能发货");
}
// 其他方法类似...
}
// 上下文类
public class OrderContext {
private OrderState currentState;
public OrderContext() {
this.currentState = new UnpaidState();
}
public void setState(OrderState state) {
System.out.println("状态变更:"
+ currentState.getClass().getSimpleName()
+ " → "
+ state.getClass().getSimpleName());
this.currentState = state;
}
// 委托方法
public void pay() {
currentState.handlePay(this);
}
public void cancel() {
currentState.handleCancel(this);
}
// 其他操作方法...
}
核心差异对比表
特性 | 传统实现 | 状态模式 |
---|---|---|
代码结构 | 面条式代码(Spaghetti Code) | 模块化结构 |
新增状态 | 修改所有相关方法 | 新增状态类即可 |
状态转换逻辑 | 散落在各个条件分支中 | 封装在具体状态类内 |
可测试性 | 需要构造完整上下文 | 可独立测试每个状态 |
业务逻辑变更 | 高风险(影响全局) | 低风险(局部修改) |
方法复杂度 | 单个方法可能上千行 | 每个类保持单一职责 |
状态模式执行流程
sequenceDiagram
participant Client
participant Context
participant State
Client->>Context: pay()
Context->>State: handlePay()
State->>Context: setState(new PaidState)
Note over Context: 状态变更通知
Context->>PaidState: handlePay() // 新状态处理
模式优势体现
- 消除条件判断:每个状态对象知道自己的下一个状态
- 业务逻辑内聚 :支付相关操作集中在
UnpaidState
处理 - 安全状态转换:非法操作直接抛出异常(如待支付状态不能发货)
- 易于扩展 :新增"预售状态"只需实现
OrderState
接口 - 状态可追溯:通过状态类名即可明确当前状态
关键理解:把状态变成「会说话的对象」------ 每个状态对象不仅知道如何处理当前操作,还清楚自己可以转换到哪些状态。这种设计让系统像智能交通信号灯一样,每个状态自主决定后续行为。
4. 手把手实现状态模式(增强版)
4.1 完善状态接口设计
java
/**
* 订单状态接口
* 定义所有状态必须实现的操作契约
*/
public interface OrderState {
void pay(OrderContext context) throws IllegalStateException;
void cancel(OrderContext context) throws IllegalStateException;
void ship(OrderContext context) throws IllegalStateException;
void complete(OrderContext context) throws IllegalStateException;
// 获取状态名称(Java 8+ default方法)
default String getStateName() {
return this.getClass().getSimpleName();
}
}
4.2 完整状态实现(含异常处理)
待支付状态
java
public class UnpaidState implements OrderState {
@Override
public void pay(OrderContext context) {
System.out.println("[业务] 执行支付操作:");
System.out.println("1. 校验支付金额");
System.out.println("2. 调用支付网关");
System.out.println("3. 更新账户余额");
context.setState(new PaidState());
}
@Override
public void cancel(OrderContext context) {
System.out.println("[业务] 执行取消操作:");
System.out.println("1. 释放库存锁定");
System.out.println("2. 清除优惠券");
context.setState(new CancelledState());
}
@Override
public void ship(OrderContext context) {
throw new IllegalStateException("待支付状态不能发货");
}
@Override
public void complete(OrderContext context) {
throw new IllegalStateException("待支付状态不能完成");
}
}
已支付状态
java
public class PaidState implements OrderState {
@Override
public void pay(OrderContext context) {
throw new IllegalStateException("已支付状态不能重复支付");
}
@Override
public void cancel(OrderContext context) {
System.out.println("[业务] 执行支付后取消:");
System.out.println("1. 发起退款流程");
System.out.println("2. 通知财务系统");
context.setState(new CancelledState());
}
@Override
public void ship(OrderContext context) {
System.out.println("[业务] 执行发货操作:");
System.out.println("1. 生成物流单号");
System.out.println("2. 通知仓库出库");
context.setState(new ShippedState());
}
@Override
public void complete(OrderContext context) {
throw new IllegalStateException("已支付状态不能直接完成");
}
}
4.3 增强上下文类实现
java
/**
* 订单上下文(状态容器)
* 1. 维护当前状态
* 2. 提供状态操作入口
* 3. 支持状态变更监听
*/
public class OrderContext {
private OrderState currentState;
private final List<StateChangeListener> listeners = new ArrayList<>();
public OrderContext() {
transitionTo(new UnpaidState());
}
// 状态转换核心方法
private void transitionTo(OrderState state) {
OrderState oldState = this.currentState;
this.currentState = state;
// 触发状态变更事件
notifyListeners(oldState, state);
}
// 添加监听器
public void addListener(StateChangeListener listener) {
listeners.add(listener);
}
private void notifyListeners(OrderState oldState, OrderState newState) {
listeners.forEach(listener ->
listener.onStateChanged(
oldState.getStateName(),
newState.getStateName()
)
);
}
// 委托方法
public void pay() {
currentState.pay(this);
}
public void cancel() {
currentState.cancel(this);
}
public void ship() {
currentState.ship(this);
}
public void complete() {
currentState.complete(this);
}
// 包可见的setter(仅允许状态类修改)
void setState(OrderState state) {
transitionTo(state);
}
// 状态变更监听接口
public interface StateChangeListener {
void onStateChanged(String oldState, String newState);
}
}
4.4 完整状态流程图解
stateDiagram-v2
[*] --> Unpaid
Unpaid --> Paid : pay()
Unpaid --> Cancelled : cancel()
Paid --> Shipped : ship()
Paid --> Cancelled : cancel()
Shipped --> Completed : complete()
Shipped --> Refunding : refund()
Refunding --> Cancelled : refundSuccess()
Refunding --> Shipped : cancelRefund()
4.5 使用示例
java
public class Client {
public static void main(String[] args) {
OrderContext order = new OrderContext();
// 添加状态变更监听
order.addListener((oldState, newState) ->
System.out.printf("状态变更通知:%s → %s%n", oldState, newState)
);
order.pay(); // 支付操作
order.ship(); // 发货操作
order.complete();// 完成订单
try {
order.cancel(); // 尝试在完成状态取消
} catch (IllegalStateException e) {
System.out.println("操作失败:" + e.getMessage());
}
}
}
4.6 设计亮点解析
- 状态隔离:每个状态类独立处理自己的业务逻辑,互不影响
- 安全封装 :
setState
方法包可见,防止外部随意修改状态- 非法操作直接抛出异常,避免状态混乱
- 扩展机制 :
- 通过监听器模式支持状态变更通知
- 方便集成日志、监控等横切关注点
- 业务可见性 :
- 状态名称自动获取,避免硬编码
- 每个操作都包含详细的业务步骤注释
- 线程安全 :
- 无共享可变状态
- 状态转换使用原子操作
最佳实践建议:
- 将状态类设为不可变对象(无状态字段)
- 使用枚举管理所有状态实例(如果状态无行为差异)
- 结合Spring等框架时,可以将状态类注册为Bean
- 为每个状态类编写独立的单元测试
5. 模式进阶与优化
5.1 状态转换管理器(高级实现)
核心思想:将状态转换规则抽象为可配置结构
graph TD
A[事件触发] --> B{状态转换管理器}
B -->|查询转换规则| C[转换规则配置]
C --> D[获取目标状态]
D --> E[创建新状态实例]
实现代码示例:
java
// 转换规则配置类
public class TransitionConfig {
private Map<StateEventPair, Class<? extends OrderState>> rules = new HashMap<>();
public void addRule(String currentState, String event, Class<? extends OrderState> targetState) {
rules.put(new StateEventPair(currentState, event), targetState);
}
public Class<? extends OrderState> getTargetState(String currentState, String event) {
return rules.get(new StateEventPair(currentState, event));
}
// 状态-事件组合键
private record StateEventPair(String state, String event) {}
}
// 增强版上下文类
public class OrderContext {
private OrderState currentState;
private final TransitionConfig transitionConfig;
public void handleEvent(String event) {
Class<? extends OrderState> targetState = transitionConfig.getTargetState(
currentState.getStateName(),
event
);
if (targetState != null) {
transitionTo(instantiateState(targetState));
}
}
private OrderState instantiateState(Class<? extends OrderState> stateClass) {
try {
return stateClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("状态初始化失败", e);
}
}
}
// YAML配置示例
transitions:
- current: UNPAID
event: PAY
target: PAID
- current: UNPAID
event: CANCEL
target: CANCELLED
优势对比:
维度 | 原生状态模式 | 配置化状态模式 |
---|---|---|
修改转换规则 | 需要修改Java代码 | 修改配置文件即可 |
规则可视化 | 需要阅读代码 | 配置文件一目了然 |
动态更新 | 需要重新部署 | 支持热更新(需配合配置中心) |
学习成本 | 需要理解状态类交互 | 配置即文档 |
5.2 与工作流引擎深度集成
架构示意图
graph LR
A[业务系统] --> B[状态模式上下文]
B --> C[工作流引擎适配层]
C --> D[(工作流引擎)]
D --> E[流程实例存储]
D --> F[流程监控看板]
集成实现示例(以Camunda为例)
java
public class WorkflowOrderState implements OrderState {
private final ProcessEngine camunda;
private final String processInstanceId;
@Override
public void ship(OrderContext context) {
// 通过工作流引擎推进流程
camunda.getRuntimeService()
.createMessageCorrelation("SHIP_EVENT")
.processInstanceId(processInstanceId)
.correlate();
// 从引擎获取最新状态
String newState = camunda.getRuntimeService()
.getVariable(processInstanceId, "currentState");
context.setState(createState(newState));
}
}
// 流程定义示例(BPMN 2.0)
<process id="order_flow">
<startEvent id="start" />
<sequenceFlow sourceRef="start" targetRef="unpaid" />
<serviceTask id="payment"
camunda:expression="${order.pay()}" />
<sequenceFlow sourceRef="unpaid" targetRef="paid" />
<exclusiveGateway id="decision" />
<sequenceFlow sourceRef="paid" targetRef="shipped">
<conditionExpression>${event == 'SHIP'}</conditionExpression>
</sequenceFlow>
</process>
工作流集成优势表
功能点 | 原生状态模式 | 工作流集成版 |
---|---|---|
流程可视化 | 需要额外开发 | 自带流程设计器 |
人工审批节点 | 无法原生支持 | 天然支持人工任务 |
流程版本控制 | 需要自行实现 | 引擎内置版本管理 |
历史轨迹追溯 | 需要额外记录日志 | 自动保存执行历史 |
SLA监控 | 需要定制开发 | 内置超时报警机制 |
分布式事务 | 实现复杂 | 支持补偿事务机制 |
5.3 混合架构实践建议
推荐场景组合方案:
pie
title 状态管理方案选择
"纯状态模式" : 20
"配置化状态机" : 35
"工作流引擎集成" : 45
决策树指南
是否需要以下特性?
├── 是 → 选择工作流引擎集成
│ ├── 需要人工审批节点
│ ├── 流程需要动态调整
│ └── 需要可视化监控
│
├── 否 → 是否需要频繁修改流程?
│ ├── 是 → 选择配置化状态机
│ └── 否 → 使用原生状态模式
性能优化技巧
- 状态对象池化:对无状态的状态对象进行复用
- 懒加载策略:按需初始化工作流引擎连接
- 异步状态转换:非关键路径操作使用事件驱动
java
// 异步转换示例
public void asyncHandleEvent(String event) {
executorService.submit(() -> {
currentState.handleEvent(this, event);
});
}
架构师提示 :
在大型分布式系统中,建议采用分层架构:
- 业务层使用轻量级状态模式
- 复杂流程委托给工作流引擎
- 通过配置中心管理状态转换规则
这种混合方案兼顾灵活性与性能,是电商、金融等复杂系统的常用实践
6. 最佳实践与陷阱
6.1 适用场景深度解析
场景一:多态行为控制器
graph TD
A[智能家居系统] --> B[工作模式]
B --> C[居家模式]
B --> D[离家模式]
B --> E[睡眠模式]
C --> F[自动开灯]
C --> G[开启安防]
D --> H[关闭所有设备]
E --> I[调暗灯光]
典型特征:
- 同一操作在不同模式下表现不同
- 模式切换时需要重置部分状态
- 存在默认模式与特殊模式
场景二:复杂流程引擎
java
// 保险理赔流程状态示例
public enum ClaimState {
INITIAL, // 初始状态
DATA_COLLECTING, // 资料收集中
UNDER_REVIEW, // 人工审核
AUTO_REVIEW, // 系统审核
PAYMENT_PENDING, // 待打款
CLOSED // 已结案
}
判断标准:
- 状态数量 ≥ 3 且存在交叉转换
- 存在逆向流程(如审核退回)
- 需要记录状态变更轨迹
场景三:游戏角色系统
stateDiagram-v2
[*] --> Idle
Idle --> Running : 移动
Idle --> Attacking : 攻击
Attacking --> Dead : 受到致命伤害
Running --> Jumping : 跳跃
Jumping --> Falling : 到达顶点
Falling --> Idle : 落地
关键指标:
- 状态转换频率高(每秒多次)
- 需要处理状态叠加(如中毒+减速)
- 存在状态优先级机制
6.2 常见误区与解决方案
陷阱一:状态类持有上下文引用
错误示例:
java
public class BadState implements OrderState {
private OrderContext context; // 危险!
public void handle() {
context.doSomething();
}
}
后果:
- 内存泄漏风险
- 状态对象无法复用
- 产生循环依赖
解决方案:
java
public class SafeState implements OrderState {
public void handle(OrderContext context) { // 通过参数传递
context.doSomething();
}
}
陷阱二:线程安全问题
并发场景分析:
sequenceDiagram
participant ThreadA
participant Context
participant ThreadB
ThreadA->>Context: setState(StateA)
ThreadB->>Context: setState(StateB)
Note over Context: 最终状态不确定!
防御策略:
- 使用不可变状态对象
java
public final class ImmutableState implements OrderState {
// 所有字段final
public void handle(OrderContext context) {
// 不修改自身状态
}
}
- 同步控制(适用于高频访问)
java
public class SyncContext {
private final ReentrantLock lock = new ReentrantLock();
private OrderState state;
public void setState(OrderState newState) {
lock.lock();
try {
this.state = newState;
} finally {
lock.unlock();
}
}
}
陷阱三:状态膨胀失控
问题表现:
pie
title 状态类数量增长
"核心业务状态" : 3
"异常处理状态" : 5
"日志记录状态" : 2
"监控上报状态" : 4
治理方案:
- 状态分层:
java
// 基础状态
interface BaseState {
void commonAction();
}
// 业务扩展状态
interface BizState extends BaseState {
void bizAction();
}
// 监控扩展状态
interface MonitorState extends BaseState {
void reportMetrics();
}
- 状态组合:
java
public class CompositeState implements OrderState {
private final List<OrderState> states = new ArrayList<>();
public void addState(OrderState state) {
states.add(state);
}
public void pay(OrderContext context) {
states.forEach(s -> s.pay(context));
}
}
6.3 黄金实践清单
设计原则检查表
- 每个状态类代码行数 ≤ 200
- 状态转换条件明确文档化
- 存在统一的状态异常处理
- 状态变更日志可追溯
- 单元测试覆盖所有转换路径
性能优化指南
- 状态预加载:
java
public class StateFactory {
private static final Map<String, OrderState> states = Map.of(
"UNPAID", new UnpaidState(),
"PAID", new PaidState()
);
public static OrderState getState(String key) {
return states.get(key);
}
}
- 状态缓存策略:
java
public class CachedState implements OrderState {
private final OrderState realState;
private LocalDateTime expiredTime;
public void handle(OrderContext context) {
if (LocalDateTime.now().isAfter(expiredTime)) {
refreshState();
}
realState.handle(context);
}
}
调试技巧
- 状态跟踪器:
java
public class DebugContext extends OrderContext {
@Override
public void setState(OrderState state) {
System.out.println("[DEBUG] 状态变更: "
+ getCurrentStateName() + " → "
+ state.getStateName());
super.setState(state);
}
}
- 状态快照:
java
public class StateSnapshot {
public static String dump(OrderContext context) {
return String.format("""
Current State: %s
Thread: %s
Stack Trace: %s
""", context.getState(),
Thread.currentThread().getName(),
Arrays.toString(Thread.currentThread().getStackTrace()));
}
}
架构师忠告 :
状态模式不是银弹,当发现以下信号时需考虑重构:
- 状态类开始出现重复代码
- 新增状态需要修改超过3个已有类
- 状态转换出现循环依赖
此时可考虑引入状态机DSL或工作流引擎进行升级改造。
7. 项目实战建议
7.1 识别适用场景(真实案例解析)
场景一:OA审批流程系统
stateDiagram-v2
[*] --> 草稿
草稿 --> 已提交 : 提交申请
已提交 --> 部门审批中 : 流转
部门审批中 --> 总经理审批中 : 通过
部门审批中 --> 已驳回 : 拒绝
总经理审批中 --> 已完成 : 通过
总经理审批中 --> 部门审批中 : 退回修改
已驳回 --> 已提交 : 重新提交
改造收益:
- 审批规则变更时只需修改对应状态类
- 新增审批节点不影响现有逻辑
- 审批日志自动记录状态变更轨迹
场景二:MMORPG角色状态系统
java
// 游戏角色状态接口
public interface CharacterState {
void move(Character character);
void attack(Character target);
void takeDamage(int damage);
void heal(int amount);
}
// 中毒状态实现
public class PoisonedState implements CharacterState {
private int remainingTurns = 3;
@Override
public void move(Character character) {
System.out.println("移动速度降低50%");
character.setSpeed(character.getBaseSpeed() * 0.5f);
remainingTurns--;
checkStateEnd(character);
}
private void checkStateEnd(Character character) {
if(remainingTurns <= 0) {
character.setState(new NormalState());
}
}
// 其他方法实现...
}
设计亮点:
- 状态叠加通过组合模式实现
- 状态持续时间内置管理
- 状态效果自动解除
场景三:物联网温控设备
classDiagram
class DeviceContext {
-state: DeviceState
+setTemperature(float)
+reportStatus()
}
class DeviceState {
+cool()
+heat()
+emergencyStop()
}
class NormalState {
+cool()
+heat()
}
class OverheatState {
+emergencyStop()
}
DeviceContext --> DeviceState
业务价值:
- 不同状态下的温度控制策略隔离
- 紧急状态自动触发保护机制
- 设备模式切换零延迟
7.2 代码重构四步法(实战演示)
原始代码(重构前)
java
public class Order {
private String status; // 待支付/已支付/已发货
public void handleEvent(String event) {
if ("待支付".equals(status)) {
if ("支付".equals(event)) {
status = "已支付";
// 支付逻辑...
} else if ("取消".equals(event)) {
status = "已取消";
// 取消逻辑...
}
} else if ("已支付".equals(status)) {
if ("发货".equals(event)) {
status = "已发货";
// 发货逻辑...
}
}
// 更多条件分支...
}
}
第一步:识别状态变量
diff
public class Order {
- private String status;
+ private OrderStatus status; // 枚举化状态
+ public enum OrderStatus {
+ UNPAID, PAID, SHIPPED, CANCELLED
+ }
}
第二步:创建状态接口
java
public interface OrderState {
void handlePayment(Order context);
void handleCancel(Order context);
void handleShipment(Order context);
void handleRefund(Order context);
}
第三步:搬移条件分支
java
// 待支付状态实现
public class UnpaidState implements OrderState {
@Override
public void handlePayment(Order context) {
// 支付逻辑
context.setState(new PaidState());
}
@Override
public void handleCancel(Order context) {
// 取消逻辑
context.setState(new CancelledState());
}
@Override
public void handleShipment(Order context) {
throw new IllegalStateException("待支付状态不能发货");
}
}
第四步:替换状态判断
java
public class Order {
private OrderState currentState;
public void handleEvent(String event) {
switch(event) {
case "支付" -> currentState.handlePayment(this);
case "取消" -> currentState.handleCancel(this);
case "发货" -> currentState.handleShipment(this);
}
}
void setState(OrderState newState) {
System.out.println("状态变更: "
+ currentState.getClass().getSimpleName()
+ " → "
+ newState.getClass().getSimpleName());
this.currentState = newState;
}
}
7.3 重构效果对比
graph LR
A[原始代码] -->|方法行数 200+| B[维护成本高]
C[重构后代码] -->|平均类行数 50| D[扩展成本低]
subgraph 复杂度变化
B -.-> E[修改涉及多个方法]
D -.-> F[仅修改单个状态类]
end
量化收益:
- 圈复杂度从 28 降至 5
- 单元测试覆盖率从 45% 提升至 95%
- 新增状态开发时间从 2天 缩短至 2小时
7.4 脚手架代码生成
java
// 使用注解处理器自动生成状态机框架
@StateMachine(
states = {"UNPAID", "PAID", "SHIPPED"},
events = {"PAY", "CANCEL", "SHIP"}
)
public class OrderStateMachine {
// 自动生成状态转换方法
// 生成状态转移图文档
// 创建基础测试用例
}
项目导入指南:
- 从最复杂的业务状态开始重构
- 使用IDE的「提取方法对象」功能快速创建状态类
- 优先处理高频变更的状态逻辑
- 配合SonarQube监控圈复杂度变化
- 采用特征开关逐步替换旧逻辑