Spring Data JPA Criteria Query代码重构:简化if-else嵌套逻辑
重构Spring Data JPA中嵌套if-else逻辑的建议
你的这段代码里嵌套的if-else确实会随着业务扩展变得难以维护,我们可以用策略模式或者**映射表(Map)**来替代这种分支判断,让代码更清晰、更易扩展。至于是否要为每个操作单独写方法,答案是肯定的——拆分后每个方法只做一件事,符合单一职责原则,也方便后续的单元测试和修改。
第一步:拆分每个条件对应的处理逻辑为独立方法
先把每个key对应的Predicate创建逻辑抽成单独的私有方法,这样每个方法的职责非常明确:
private static Predicate handleStartDate(Root<Entitlement> entitlement, CriteriaBuilder cb, String value) { return cb.greaterThanOrEqualTo(entitlement.get(Constants.START_DATE), DateUtil.convertString(value)); } private static Predicate handleEndDate(Root<Entitlement> entitlement, CriteriaBuilder cb, String value) { return cb.lessThanOrEqualTo(entitlement.get(Constants.END_DATE), DateUtil.convertString(value)); } private static Predicate handleQntGranted(Root<Entitlement> entitlement, CriteriaBuilder cb, String value) { return cb.greaterThan(entitlement.get(Constants.QNT_GRANTED), value); } private static Predicate handleValueGranted(Root<Entitlement> entitlement, CriteriaBuilder cb, String value) { return cb.greaterThan(entitlement.get(Constants.VALUE_GRANTED), value); } private static Predicate handleCommaSeparatedValue(Root<Entitlement> entitlement, CriteriaBuilder cb, String key, String value) { return entitlement.get(key).in(Arrays.asList(StringUtils.split(value))); } private static Predicate handleEqualCondition(Root<Entitlement> entitlement, CriteriaBuilder cb, String key, String value) { return cb.equal(entitlement.get(key), value); }
第二步:用Map建立key和处理方法的映射
我们可以创建一个静态的映射表,把每个key和对应的处理逻辑绑定,这样就能彻底消除if-else嵌套。这里需要自定义一个TriFunction接口来适配三个参数的处理方法:
// 自定义函数式接口,适配三个输入参数的场景 @FunctionalInterface interface TriFunction<A, B, C, R> { R apply(A a, B b, C c); } // 静态初始化映射表,绑定key与对应处理器 private static final Map<String, TriFunction<Root<Entitlement>, CriteriaBuilder, String, Predicate>> FILTER_HANDLERS = Map.of( Constants.START_DATE, YourClassName::handleStartDate, Constants.END_DATE, YourClassName::handleEndDate, Constants.QNT_GRANTED, YourClassName::handleQntGranted, Constants.VALUE_GRANTED, YourClassName::handleValueGranted );
第三步:重构原方法,用映射表替代if-else
现在原方法就变得非常简洁,逻辑一目了然:
private static void buildEntitlementFilterQuery(Root<Entitlement> entitlement, CriteriaBuilder cb, List<Predicate> predicates, Entry<String, String> entry) { String key = entry.getKey().toUpperCase(); // 统一转大写,避免重复equalsIgnoreCase判断 String value = entry.getValue(); if (StringUtils.isNotBlank(value)) { Predicate predicate; // 从映射表获取对应处理器 TriFunction<Root<Entitlement>, CriteriaBuilder, String, Predicate> handler = FILTER_HANDLERS.get(key); if (handler != null) { predicate = handler.apply(entitlement, cb, value); } else { // 处理通用情况:逗号分隔值或相等判断 predicate = StringUtils.contains(value, Constants.COMMA) ? handleCommaSeparatedValue(entitlement, cb, key, value) : handleEqualCondition(entitlement, cb, key, value); } // 用and包装后加入predicate列表 predicates.add(cb.and(predicate)); } }
额外优化点
- 统一key的大小写:把entry.getKey()转成大写(或小写),避免每次重复使用
equalsIgnoreCase判断,既提升性能也让代码更简洁。 - 扩展性:以后新增过滤条件时,只需要新增一个处理方法,然后在
FILTER_HANDLERS里加一行映射即可,完全不需要修改原方法逻辑,符合开闭原则。 - 可测试性:每个独立的处理方法都可以单独编写单元测试,验证逻辑正确性,排查问题更高效。
内容的提问来源于stack exchange,提问作者Ankur Goel
相关产品推荐
相关产品推荐

