以游戏租号应用的订单处理流程为例,系统需要根据订单类型(租赁、商城、会员)执行不同的业务规则。在租赁订单的处理中,需要检查库存、判断是否预约、应用优惠券,最后完成支付;而商城订单则只需要检查库存、应用优惠券,最后完成支付;会员订单则需要计算权益、应用优惠券,最终完成支付。如何优雅地管理这些复杂的业务规则,同时确保代码的可维护性和扩展性?
1. 传统责任链模式的局限性
责任链模式 是一种常见的设计模式,适用于线性流程的业务场景,例如日志处理、请求拦截、审批流等。在游戏租号的订单处理中,我们可以使用责任链模式,将各个订单处理环节(库存检查、会员折扣、优惠券、支付)串联起来,让请求依次经过各个处理器: 每个处理器执行自己的逻辑,并决定是否继续传递请求。
代码实现
1. 订单上下文
java
@Data
public class OrderContext {
private Order order;
}
2. 订单处理器接口
java
public interface OrderHandler {
/**
* 规则树处理
*
* @param orderContext 订单上下文
* @param chain 执行器
*/
void handle(OrderContext orderContext, OrderHandlerChain chain);
}
3. 责任链执行器
java
@Slf4j
@Component
public class OrderHandlerChain {
@Resource
private List<OrderHandler> handlers;
private int index = 0;
public void proceed(OrderContext context) {
if (index < handlers.size()) {
handlers.get(index++).handle(context, this);
}
}
}
4. 库存处理
java
@Slf4j
@Component
@Order(1)
public class StockCheckHandler implements OrderHandler {
@Override
public void handle(OrderContext orderContext, OrderHandlerChain chain) {
log.info("进入租赁库存检查: {}", JSON.toJSONString(orderContext));
// 判断订单类型
PaymentOrderTypeEnum orderType = PaymentOrderTypeEnum.valueOfByType(orderContext.getOrder().getOrderType());
if (orderType == PaymentOrderTypeEnum.RENTAL) {
// TODO 租赁逻辑
// 判断库存情况,决定是否预约
if (/* 库存不足 */) {
log.info("库存不足,进行预约");
// TODO 预约逻辑
} else {
log.info("库存充足,直接下单");
// TODO 非预约逻辑
}
} else if (orderType == PaymentOrderTypeEnum.MALL) {
// TODO 商城逻辑
} else if (orderType == PaymentOrderTypeEnum.MEMBER) {
// TODO 会员逻辑
}
chain.proceed(orderContext);
}
}
5. 优惠券处理
java
@Slf4j
@Component
@Order(2)
public class CouponHandler implements OrderHandler {
@Override
public void handle(OrderContext orderContext, OrderHandlerChain chain) {
log.info("进入优惠券处理器: {}", JSON.toJSONString(orderContext));
// TODO 优惠券处理
chain.proceed(orderContext);
}
}
6. 支付处理
java
@Slf4j
@Component
@Order(3)
public class PaymentHandler implements OrderHandler {
@Override
public void handle(OrderContext orderContext, OrderHandlerChain chain) {
// TODO 支付处理
chain.proceed(orderContext);
}
}
然而,责任链模式的局限性 也很明显:
- 线性执行,无法跳跃或分支 ------ 订单处理流程并不是单一的顺序,而是会根据订单类型和是否预约走不同的流程。
- 规则增加后,链条可能变得过长 ------ 责任链适用于流程固定的场景,但当业务规则越来越复杂时,代码可读性和性能都会下降。
- 缺乏灵活性 ------ 任何新增的处理逻辑,都需要改动链条上的代码,难以动态调整规则。
2. 规则树模式:灵活的决策流
为了解决责任链的局限性,我们可以引入 规则树模式 ,用树状结构替代线性执行。规则树的核心思想是:每个节点代表一个决策点,后续执行路径由业务规则动态决定,而不是简单的顺序执行。
在我们的订单处理场景中,订单首先会被订单分流处理器 分类:
- 如果是租赁订单,进入库存检查处理器,再根据是否预约进入不同的分支。
- 如果是商城订单,直接进入商城库存处理器。
- 如果是会员订单,进入会员逻辑。
代码实现
1. 订单上下文对象
java
@Data
public class OrderContext {
/**
* 订单对象
*/
private Order order;
/**
* 是否预约
*/
private boolean isReserve;
}
2. 订单规则树处理接口
java
public interface OrderHandler {
/**
* 规则树处理
*
* @param orderContext 订单上下文
*/
void handle(OrderContext orderContext);
/**
* 获取下一个处理器
*
* @return 下一个处理器
*/
OrderHandler next(OrderContext orderContext);
}
3. 订单规则树抽象类
java
public abstract class AbstractOrderHandler implements OrderHandler {
/**
* 判断是否存在下一个处理器
*
* @param orderContext 上下文
* @return 是否存在下一个处理器
*/
public boolean hasNext(OrderContext orderContext) {
return next(orderContext) != null;
}
}
4. 规则树执行器
java
@Slf4j
@Component
public class OrderHandlerChain {
// 首节点
@Resource
private OrderShuntHandler orderShuntHandler;
@Resource
private PlatformTransactionManager platformTransactionManager;
/**
* 执行规则树
*
* @param context 上下文
*/
public void proceed(OrderContext context) {
TransactionStatus transaction = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// 执行规则树
OrderHandler currentHandler = orderShuntHandler;
while (currentHandler != null) {
currentHandler.handle(context);
currentHandler = currentHandler.next(context);
}
platformTransactionManager.commit(transaction);
} catch (Exception e) {
log.error("订单规则树执行异常: {}", e.getMessage(), e);
platformTransactionManager.rollback(transaction);
throw e;
}
}
}
5. 订单类型分流处理器
java
@Slf4j
@Component
public class OrderShuntHandler extends AbstractOrderHandler {
@Resource
private RentStockCheckHandler rentStockCheckHandler;
@Resource
private MallStockCheckHandler mallStockCheckHandler;
@Resource
private MemberHandler memberHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入租赁与商城订单分流: {}", JSON.toJSONString(orderContext));
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
PaymentOrderTypeEnum orderType = PaymentOrderTypeEnum.valueOfByType(orderContext.getOrder().getOrderType());
if (orderType == PaymentOrderTypeEnum.RENTAL) {
return rentStockCheckHandler;
} else if (orderType == PaymentOrderTypeEnum.MALL) {
return mallStockCheckHandler;
} else if (orderType == PaymentOrderTypeEnum.MEMBER) {
return memberHandler;
}
return null;
}
}
6. 租赁库存校验
java
@Slf4j
@Component
public class RentStockCheckHandler extends AbstractOrderHandler {
@Resource
private ReserveHandler reserveHandler;
@Resource
private NoReserveHandler noReserveHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入租赁库存处理器: {}", JSON.toJSONString(orderContext));
// 是否预约
orderContext.setReserve(true);
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
if (orderContext.isReserve()) {
return reserveHandler;
}
return noReserveHandler;
}
}
7. 预约 与 非预约处理器
java
@Slf4j
@Component
public class ReserveHandler extends AbstractOrderHandler {
@Resource
private CouponHandler couponHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入预约处理器: {}", JSON.toJSONString(orderContext));
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
return couponHandler;
}
}
--------------------------------------------------------------------------
@Slf4j
@Component
public class NoReserveHandler extends AbstractOrderHandler {
@Resource
private CouponHandler couponHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入非预约处理器: {}", JSON.toJSONString(orderContext));
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
return couponHandler;
}
}
8. 优惠券处理器
java
@Slf4j
@Component
public class CouponHandler extends AbstractOrderHandler {
@Resource
private PaymentHandler paymentHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入优惠券处理器: {}", JSON.toJSONString(orderContext));
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
return paymentHandler;
}
}
9. 支付处理器
java
@Slf4j
@Component
public class PaymentHandler extends AbstractOrderHandler {
@Override
public void handle(OrderContext orderContext) {
log.info("进入支付处理器: {}", JSON.toJSONString(orderContext));
// TODO 业务实现
}
@Override
public OrderHandler next(OrderContext orderContext) {
return null;
}
}
10. 商城库存处理器
java
@Slf4j
@Component
public class MallStockCheckHandler extends AbstractOrderHandler {
@Resource
private CouponHandler couponHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入商城库存处理器: {}", JSON.toJSONString(orderContext));
// 业务处理
}
@Override
public OrderHandler next(OrderContext orderContext) {
return couponHandler;
}
}
11. 会员处理器
java
@Slf4j
@Component
public class MemberHandler extends AbstractOrderHandler {
@Resource
private CouponHandler couponHandler;
@Override
public void handle(OrderContext orderContext) {
log.info("进入会员处理器: {}", JSON.toJSONString(orderContext));
}
@Override
public OrderHandler next(OrderContext orderContext) {
return couponHandler;
}
}
12. 测试
java
public class OrderTest {
@Resource
private OrderHandlerChain orderHandlerChain;
@Test
public void test() {
Order order = new Order();
order.setId("1");
order.setOrderNo("220123123883");
order.setOrderType(PaymentOrderTypeEnum.RENTAL.getType());
order.setPayType(PaymentWayEnum.BALANCE_PAYMENT.getWay());
order.setOrderUserId("qfxl");
order.setCouponId("");
OrderContext orderContext = new OrderContext();
orderContext.setOrder(order);
orderHandlerChain.proceed(orderContext);
}
}
租赁非预约
租赁预约
商城
会员流程:
规则树模式的优势
相较于传统的责任链模式,规则树模式提供了更灵活的决策路径,适用于复杂的业务场景。
✅ 更灵活的流程控制 :支持不同路径的分支处理,而不是一条链条执行到底。
✅ 更好的扩展性 :新增规则只需增加节点,不需要改动其他代码。
✅ 更高的执行效率 :避免无意义的遍历,提升处理速度。
总结
在订单处理系统中,责任链模式适用于简单的线性流程,而规则树模式更适用于复杂的业务规则 。如果你的系统涉及多种决策逻辑,规则树模式将是更优的选择。
你在业务中是否遇到过类似的规则决策问题?可以试试用规则树优化! 🚀