#状态模式与责任链模式
#一个订单状态机的 if-else 噩梦
我们团队有个订单系统,状态机是这样的:
public void handle(Order order, String action) {
if ("PAID".equals(order.getStatus())) {
if ("DELIVER".equals(action)) {
order.setStatus("DELIVERING");
notifyDelivery(order);
} else if ("CANCEL".equals(action)) {
order.setStatus("CANCELLED");
refund(order);
}
} else if ("DELIVERING".equals(order.getStatus())) {
if ("RECEIVE".equals(action)) {
order.setStatus("COMPLETED");
addPoints(order);
} else if ("REFUND".equals(action)) {
order.setStatus("REFUNDING");
startRefund(order);
}
} else if ("COMPLETED".equals(order.getStatus())) {
if ("REFUND".equals(action)) {
order.setStatus("REFUNDING");
startRefund(order);
}
} else if ("CANCELLED".equals(order.getStatus())) {
// 终止状态,大部分 action 无效
throw new IllegalStateException("Order already cancelled");
}
// ...
}两年下来,这个方法积累了 47 个 if-else,每个新状态都要小心翼翼地理解现有逻辑。
这就是状态模式要解决的问题:把状态的转换逻辑从条件分支中分离出来。
#二、状态模式核心结构🔴
#2.1 标准写法
// 订单状态接口
interface OrderState {
void pay(OrderContext context);
void deliver(OrderContext context);
void receive(OrderContext context);
void cancel(OrderContext context);
void refund(OrderContext context);
String getStateName();
}
// 上下文:持有当前状态
class OrderContext {
private OrderState state;
private final Order order;
public OrderContext(Order order, OrderState initialState) {
this.order = order;
this.state = initialState;
}
public void setState(OrderState state) {
this.state = state;
}
public Order getOrder() {
return order;
}
// 委托给当前状态处理
public void pay() { state.pay(this); }
public void deliver() { state.deliver(this); }
public void receive() { state.receive(this); }
public void cancel() { state.cancel(this); }
}
// 具体状态:待支付
class AwaitingPaymentState implements OrderState {
@Override
public void pay(OrderContext context) {
context.getOrder().setStatus("PAID");
context.setState(new PaidState());
// 发送通知
}
@Override
public void deliver(OrderContext context) {
throw new IllegalStateException("Cannot deliver before payment");
}
@Override
public void cancel(OrderContext context) {
context.getOrder().setStatus("CANCELLED");
context.setState(new CancelledState());
}
@Override
public void receive(OrderContext context) { /* 无效 */ }
@Override
public void refund(OrderContext context) { /* 无效 */ }
@Override
public String getStateName() { return "AWAITING_PAYMENT"; }
}
// 具体状态:已支付
class PaidState implements OrderState {
@Override
public void pay(OrderContext context) {
// 重复支付?忽略或报错
}
@Override
public void deliver(OrderContext context) {
context.getOrder().setStatus("DELIVERING");
context.setState(new DeliveringState());
notifyDelivery(context.getOrder());
}
@Override
public void cancel(OrderContext context) {
context.getOrder().setStatus("CANCELLED");
context.setState(new CancelledState());
refund(context.getOrder());
}
@Override
public void receive(OrderContext context) { /* 无效 */ }
@Override
public void refund(OrderContext context) { /* 无效 */ }
@Override
public String getStateName() { return "PAID"; }
}
// 具体状态:配送中
class DeliveringState implements OrderState {
@Override
public void receive(OrderContext context) {
context.getOrder().setStatus("COMPLETED");
context.setState(new CompletedState());
addPoints(context.getOrder());
}
@Override
public void refund(OrderContext context) {
context.getOrder().setStatus("REFUNDING");
context.setState(new RefundingState());
startRefund(context.getOrder());
}
// 其他方法:无效或异常
@Override
public void pay(OrderContext context) { /* 无效 */ }
@Override
public void deliver(OrderContext context) { /* 无效 */ }
@Override
public void cancel(OrderContext context) { /* 无效 */ }
@Override
public String getStateName() { return "DELIVERING"; }
}
// 其他状态...#2.2 使用方式
// 订单创建后,初始状态为待支付
Order order = new Order();
OrderContext context = new OrderContext(order, new AwaitingPaymentState());
// 支付
context.pay(); // 状态流转:待支付 -> 已支付
// 发货
context.deliver(); // 状态流转:已支付 -> 配送中
// 收货
context.receive(); // 状态流转:配送中 -> 已完成
// 如果尝试在已完成后再次发货
context.deliver(); // 抛出 IllegalStateException#2.3 状态模式 vs 策略模式
| 维度 | 状态模式 | 策略模式 |
|---|---|---|
| 状态切换 | 状态对象内部决定下一步状态 | 客户端外部决定 |
| 上下文角色 | 上下文被动接收状态 | 上下文主动选择策略 |
| 状态关系 | 状态之间有转换关系 | 策略之间相互独立 |
| 使用时机 | 状态决定行为 | 行为决定选择 |
// 状态模式:状态自己决定下一个状态
class PaidState {
void deliver(OrderContext context) {
context.setState(new DeliveringState()); // 状态自己切换
}
}
// 策略模式:客户端决定用哪个策略
class DiscountContext {
void setStrategy(DiscountStrategy s) { // 客户端指定
this.strategy = s;
}
}【面试官心理】 状态模式和策略模式的区别是高频面试题。能说出"状态自己控制转换"和"客户端外部选择"的区别,说明候选人真正理解了两个模式的本质。
#三、责任链模式🔴
#3.1 标准写法
// 处理器接口
interface Handler {
void setNext(Handler handler);
void handle(Request request);
default void handleNext(Request request) {
Handler next = getNext();
if (next != null) {
next.handle(request);
}
}
Handler getNext();
}
// 请求对象
class Request {
private final String type;
private final Object data;
private boolean handled = false;
public Request(String type, Object data) {
this.type = type;
this.data = data;
}
}
// 具体处理器:认证
class AuthHandler implements Handler {
private Handler next;
@Override
public void setNext(Handler handler) {
this.next = handler;
}
@Override
public Handler getNext() {
return next;
}
@Override
public void handle(Request request) {
if (!isAuthenticated(request)) {
throw new SecurityException("Unauthorized");
}
handleNext(request); // 传递给下一个处理器
}
private boolean isAuthenticated(Request request) {
// 认证逻辑
return true;
}
}
// 具体处理器:参数校验
class ValidationHandler implements Handler {
private Handler next;
@Override
public void setNext(Handler handler) {
this.next = handler;
}
@Override
public Handler getNext() {
return next;
}
@Override
public void handle(Request request) {
if (!isValid(request)) {
throw new IllegalArgumentException("Invalid parameters");
}
handleNext(request);
}
private boolean isValid(Request request) {
// 校验逻辑
return true;
}
}
// 具体处理器:业务处理
class BusinessHandler implements Handler {
private Handler next;
@Override
public void setNext(Handler handler) {
this.next = handler;
}
@Override
public Handler getNext() {
return next;
}
@Override
public void handle(Request request) {
// 业务逻辑
System.out.println("Processing: " + request.getType());
}
}#3.2 链的组装
class HandlerChain {
private Handler head;
private Handler tail;
public void addHandler(Handler handler) {
if (head == null) {
head = handler;
tail = handler;
} else {
tail.setNext(handler);
tail = handler;
}
}
public void handle(Request request) {
if (head != null) {
head.handle(request);
}
}
}
// 组装
HandlerChain chain = new HandlerChain();
chain.addHandler(new AuthHandler());
chain.addHandler(new ValidationHandler());
chain.addHandler(new BusinessHandler());
// 处理请求
chain.handle(new Request("CREATE_ORDER", data));#3.3 Spring MVC 的拦截器链
Spring MVC 的 HandlerInterceptor 就是责任链模式的应用:
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true; // 前置处理
}
default void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 后置处理
}
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 完成处理
}
}Spring MVC 按顺序调用拦截器的 preHandle,任何一个返回 false 就中断链:
请求 → Interceptor1.preHandle (true) → Interceptor2.preHandle (true)
→ Controller → Interceptor2.postHandle → Interceptor1.postHandle#四、状态模式与责任链的结合🟡
#4.1 订单审批流程
// 状态模式处理状态转换
// 责任链处理审批流程
interface OrderApprovalChain {
void approve(OrderContext context, Approver approver);
}
// 审批人(责任链中的处理器)
interface Approver {
boolean approve(Order order);
void setNext(Approver next);
}
// 主管审批
class TeamLeadApprover implements Approver {
private Approver next;
@Override
public boolean approve(Order order) {
if (order.getAmount() <= 10000) {
order.approve();
return true;
}
return next != null && next.approve(order);
}
@Override
public void setNext(Approver next) {
this.next = next;
}
}
// 经理审批
class ManagerApprover implements Approver {
private Approver next;
@Override
public boolean approve(Order order) {
if (order.getAmount() <= 50000) {
order.approve();
return true;
}
return next != null && next.approve(order);
}
@Override
public void setNext(Approver next) {
this.next = next;
}
}#五、生产避坑清单
#5.1 状态模式的状态数量爆炸
// ❌ 错误:为每个状态-动作组合写一个状态类
class PaidToDeliveringState implements OrderState { } // 太细
class PaidToCancelledState implements OrderState { } // 太细
// ✅ 正确:状态是粗粒度的,动作在状态内部决定
class PaidState implements OrderState {
// 在一个状态类里处理所有可能的转换
}#5.2 责任链的断链问题
// ❌ 错误:忘记传递到下一个处理器
@Override
public void handle(Request request) {
// 处理了但不传递
process(request);
// 忘记调用 handleNext(request);
}
// ✅ 正确:明确知道什么时候传,什么时候断
@Override
public void handle(Request request) {
if (canHandle(request)) {
process(request);
// 处理完可以断链
} else {
handleNext(request); // 不能处理才传递
}
}⚠️
责任链模式最大的坑是"断链"——某个处理器处理完请求后忘记调用 handleNext,导致后续处理器永远得不到执行。解决方法是每个处理器必须显式决定是否传递。
#六、面试总结
#6.1 核心追问
- "状态模式和 if-else 相比有什么优势?" —— 消除分支、更改独立、状态内聚
- "状态模式和策略模式的区别?" —— 状态自己切换 vs 客户端切换
- "责任链模式的链断了怎么办?" —— 必须显式传递
#6.2 级别差异
| 级别 | 期望回答 |
|---|---|
| P5 | 能写出两种模式的基本结构 |
| P6 | 能说出状态模式和策略模式的区别 |
| P7 | 能结合 Spring MVC 分析责任链,知道状态机设计的陷阱 |