别再硬编码了!用Java模板方法模式重构你的重复业务逻辑(附Spring Boot实战案例)
每次看到代码里那些长得几乎一模一样、只有细微差别的业务逻辑处理流程,你是不是也忍不住想砸键盘?订单处理要校验->执行->记录日志->发通知,用户审核也是校验->执行->记录日志->发通知,商品上架还是这套流程...这种场景在企业级开发中简直太常见了。今天我们就来聊聊如何用模板方法模式优雅解决这个问题,让你的代码从此告别"复制粘贴"式开发。
1. 为什么你的Spring Boot项目需要模板方法模式
最近在重构一个电商后台系统时,我发现至少有8个业务模块都在重复实现相同的处理流程。比如订单取消和退货申请这两个功能,核心流程都是:
- 参数校验
- 权限验证
- 执行业务逻辑
- 记录操作日志
- 发送状态通知
唯一的区别就是第3步的具体业务实现不同。这种场景下如果每个模块都独立实现全套流程,不仅会产生大量重复代码,更可怕的是当流程需要调整时(比如新增一个风控检查环节),你得把所有相关模块都改一遍——这简直就是维护噩梦。
模板方法模式正是为解决这类问题而生。它通过:
- 固定算法骨架:在抽象类中定义不可变的流程模板
- 灵活扩展细节:允许子类重写特定步骤的实现
- 统一流程管控:所有子类共享相同的执行逻辑
在Spring生态中,这个模式尤其有用。比如你可以:
public abstract class AbstractBusinessHandler { // 模板方法设为final防止被重写 public final Result handle(Request request) { validate(request); checkPermission(request); Object result = doBusiness(request); // 抽象方法 logOperation(request); sendNotification(request); return Result.success(result); } protected abstract Object doBusiness(Request request); // 其他步骤提供默认实现 protected void validate(Request request) { // 通用校验逻辑... } // ...其他方法 }2. Spring Boot中的模板方法实战
2.1 基础实现方案
让我们用一个具体的订单处理场景来演示。假设我们需要处理三种订单操作:创建订单、取消订单和支付订单。首先定义抽象模板:
public abstract class AbstractOrderHandler { @Autowired private OperationLogService logService; @Autowired private NotificationService notifyService; public final OrderResult execute(OrderRequest request) { // 1. 参数校验 validate(request); // 2. 业务规则检查 checkBusinessRules(request); // 3. 核心业务处理(由子类实现) OrderResult result = processOrder(request); // 4. 记录日志 logService.log( request.getOperator(), getOperationType(), result.isSuccess() ); // 5. 发送通知 if (shouldNotify()) { notifyService.send( buildNotification(request, result) ); } return result; } protected abstract OrderResult processOrder(OrderRequest request); protected abstract OperationType getOperationType(); protected boolean shouldNotify() { return true; // 默认发送通知 } // ...其他通用方法 }然后实现具体的处理器:
@Service public class OrderCreateHandler extends AbstractOrderHandler { @Override protected OrderResult processOrder(OrderRequest request) { // 创建订单的具体逻辑 return orderService.create(request); } @Override protected OperationType getOperationType() { return OperationType.CREATE; } }2.2 与Spring框架的高级整合
模板方法模式在Spring中可以有更优雅的实现方式。比如结合@PostConstruct初始化处理器映射:
@Service public class OrderHandlerFactory { @Autowired private List<AbstractOrderHandler> handlers; private Map<OperationType, AbstractOrderHandler> handlerMap; @PostConstruct void init() { handlerMap = handlers.stream() .collect(Collectors.toMap( AbstractOrderHandler::getOperationType, Function.identity() )); } public AbstractOrderHandler getHandler(OperationType type) { return handlerMap.get(type); } }或者在Web层通过Command模式进一步解耦:
@RestController @RequestMapping("/orders") public class OrderController { @Autowired private OrderHandlerFactory handlerFactory; @PostMapping("/{operation}") public ResponseEntity<?> handleOrder( @PathVariable String operation, @RequestBody OrderRequest request ) { OperationType type = OperationType.from(operation); AbstractOrderHandler handler = handlerFactory.getHandler(type); return ResponseEntity.ok(handler.execute(request)); } }3. 模板方法模式的进阶技巧
3.1 钩子方法的灵活运用
钩子方法(Hook Method)可以让子类有条件地影响模板的执行流程。比如某些业务可能不需要发送通知:
public abstract class AbstractOrderHandler { // ...其他代码 protected boolean shouldNotify() { return true; // 默认发送通知 } } @Service public class OrderQueryHandler extends AbstractOrderHandler { @Override protected boolean shouldNotify() { return false; // 查询操作不需要通知 } // ...其他实现 }3.2 模板方法与策略模式的组合
当某些步骤存在多种实现方式时,可以结合策略模式:
public abstract class AbstractOrderHandler { @Autowired private ValidationStrategy validationStrategy; protected void validate(OrderRequest request) { validationStrategy.validate(request); } // ...其他代码 }3.3 性能监控的天然支持
模板方法模式非常适合添加统一的性能监控:
public abstract class AbstractOrderHandler { public final OrderResult execute(OrderRequest request) { long start = System.currentTimeMillis(); try { OrderResult result = doExecute(request); metrics.recordSuccess(getOperationType(), start); return result; } catch (Exception e) { metrics.recordFailure(getOperationType(), start); throw e; } } protected OrderResult doExecute(OrderRequest request) { // 原执行逻辑... } }4. 企业级应用中的最佳实践
4.1 流程可配置化
通过将流程步骤抽象为可配置项,可以实现更灵活的流程管理:
public abstract class AbstractBusinessHandler { @Value("${handler.steps}") private List<String> enabledSteps; public final Result handle(Request request) { Result result = new Result(); if (enabledSteps.contains("validate")) { validate(request, result); } if (enabledSteps.contains("business")) { doBusiness(request, result); } // ...其他步骤 return result; } }4.2 与工作流引擎的对比
与完整的工作流引擎相比,模板方法模式更适合相对固定的业务流程:
| 特性 | 模板方法模式 | 工作流引擎 |
|---|---|---|
| 学习成本 | 低 | 高 |
| 灵活性 | 中等 | 高 |
| 适合场景 | 固定流程+可变步骤 | 复杂多变的业务流程 |
| 维护成本 | 低 | 中到高 |
| 性能 | 高 | 中 |
4.3 异常处理统一方案
在模板中统一处理异常可以避免重复代码:
public abstract class AbstractOrderHandler { public final OrderResult execute(OrderRequest request) { try { // 正常流程... } catch (BusinessException e) { return OrderResult.fail(e.getErrorCode()); } catch (Exception e) { log.error("处理订单异常", e); return OrderResult.fail(ErrorCode.SYSTEM_ERROR); } } }5. 实际项目中的坑与解决方案
5.1 循环依赖问题
当模板类需要注入子类特有的服务时,容易产生循环依赖。解决方案:
public abstract class AbstractOrderHandler { // 改为protected setter注入 protected OrderService orderService; @Autowired public void setOrderService(OrderService orderService) { this.orderService = orderService; } }5.2 模板方法过大的问题
如果模板方法变得过于复杂,可以考虑拆分为多个模板类:
public abstract class BasicOrderHandler { // 基础校验和日志等通用逻辑 } public abstract class AdvancedOrderHandler extends BasicOrderHandler { // 更复杂的业务逻辑模板 }5.3 测试策略
测试模板类时需要特别注意:
public class AbstractOrderHandlerTest { @Test void shouldFollowTemplateSequence() { AbstractOrderHandler handler = spy(new TestOrderHandler()); handler.execute(request); InOrder inOrder = inOrder(handler); inOrder.verify(handler).validate(any()); inOrder.verify(handler).checkBusinessRules(any()); inOrder.verify(handler).processOrder(any()); // ...验证调用顺序 } static class TestOrderHandler extends AbstractOrderHandler { // 测试用实现... } }在最近的一个供应链系统中,我们使用模板方法模式重构了12个业务流程模块,代码重复率从原来的68%降到了15%以下。最明显的好处是当需要增加新的流程环节(比如新增合规检查)时,只需要修改抽象模板类一处,所有子类自动继承这一变更。