如何用Callable设计模式优化Spring Controller重复代码?
使用Callable(函数式编程)消除Spring Controller重复代码的可行方案
当然可行!你已经找对了方向——用函数式编程的思路把重复的「获取integId/orgId」逻辑抽离出来,让Controller方法只专注于请求本身的参数和业务调用。
先看看你原来的代码里的重复点:每个方法都要写一遍helper.getIntegId(request)和helper.getOrgId(request),这部分完全可以统一封装到一个通用执行方法里。下面是具体的实现方案:
首先,我们需要定义几个自定义的函数式接口(Java标准库没有现成的三元/四元函数接口),用来适配不同业务方法的参数需求:
// 三元函数接口:接收三个参数,返回一个结果 @FunctionalInterface private interface TriFunction<T, U, V, R> { R apply(T t, U u, V v); } // 四元消费接口:接收四个参数,无返回值 @FunctionalInterface private interface QuadConsumer<T, U, V, W> { void accept(T t, U u, V v, W w); }
接下来,在你的Controller里实现几个重载的通用execute方法,负责统一获取integId和orgId,然后执行传入的业务逻辑:
// 适配无额外参数的业务方法(比如getUserRules) private <T> ResponseEntity<?> execute(HttpServletRequest request, BiFunction<String, String, T> businessLogic) { String integId = helper.getIntegId(request); String orgId = helper.getOrgId(request); T result = businessLogic.apply(integId, orgId); return ResponseEntity.ok(result); } // 适配需要ruleId的查询方法(比如getRule) private <T> ResponseEntity<?> execute(HttpServletRequest request, Long ruleId, TriFunction<String, String, Long, T> businessLogic) { String integId = helper.getIntegId(request); String orgId = helper.getOrgId(request); T result = businessLogic.apply(integId, orgId, ruleId); return ResponseEntity.ok(result); } // 适配需要ruleId和请求体的更新方法(比如updateRule) private ResponseEntity<?> execute(HttpServletRequest request, Long ruleId, Object object, QuadConsumer<String, String, Long, Object> businessLogic) { String integId = helper.getIntegId(request); String orgId = helper.getOrgId(request); businessLogic.accept(integId, orgId, ruleId, object); return ApiResponse.ok(); }
现在,你原来的Controller方法就可以简化成这样,完全消除重复代码:
@GetMapping("") public ResponseEntity<?> getUserRules(HttpServletRequest request) { return execute(request, service::getUserRules); } @GetMapping("/{ruleId}") public ResponseEntity<?> getRule(HttpServletRequest request, @PathVariable Long ruleId) { return execute(request, ruleId, service::getRule); } @PutMapping("/{ruleId}") public ResponseEntity<?> updateRule(HttpServletRequest request, @PathVariable Long ruleId, @RequestBody @Valid Object object) { return execute(request, ruleId, object, service::updateRule); }
补充说明
- 这里用了方法引用(
service::getUserRules)让代码更简洁,如果你需要做额外的参数处理,也可以用lambda表达式代替,比如:(integId, orgId) -> service.someMethod(integId, orgId, otherParam) - 如果后续有更多参数的业务方法,可以继续扩展对应的函数式接口和
execute重载方法,保持Controller的清爽 - 这种方式本质是利用了函数式编程的「行为参数化」思想,和你提到的Callable设计模式思路一致——把可变的业务逻辑作为参数传入,固定的通用逻辑放在
execute里统一处理
内容的提问来源于stack exchange,提问作者Sha
相关产品推荐
相关产品推荐

