如何降低圈复杂度13(超阈值10)的isPropertyAccessed方法复杂度
问题说明
- 现有
isPropertyAccessed方法圈复杂度检测值为13,高于允许阈值10 - 优化约束:必须保留方法内全部判断条件,所有条件无重复逻辑,不得删减业务判断规则
待优化原代码如下:
private boolean isPropertyAccessed(AccessLevels readAccessLevel, Relationship relationship) { boolean isAccessed1 = readAccessLevel.isAccessed1() && relationship.getAccessed1Relationship() == ACCESSED1; boolean isAccessed2 = readAccessLevel.isAccessed2() && relationship.getAccessed2Relationship() == ACCESSED2; boolean isAccessed3 = readAccessLevel.isAccessed3() && relationship.getAccessed3Relationship() == ACCESSED3; boolean isAccessed4 = readAccessLevel.isAccessed4() && relationship.getAccessed4Relationship() == ACCESSED4; boolean isAccessed5 = readAccessLevel.isAccessed5() && relationship.getAccessed5Relationship() == ACCESSED5; boolean isAccessed6 = readAccessLevel.isAccessed6() && relationship.getAccessed6Relationship() == ACCESSED6; return readAccessLevel.isAll() || isAccessed1 || isAccessed2 || isAccessed3 || isAccessed4 || isAccessed5 || isAccessed6; }
复杂度偏高原因
圈复杂度统计规则会将每个逻辑与(&&)、逻辑或(||)、条件分支、循环都计为独立分支节点:原代码包含1个基础执行路径、6个&&判断、6个||判断,合计复杂度为1+6+6=13,和检测结果一致。
优化方案
优先推荐延迟判断+短路遍历实现,在绝大多数业务场景下(判断逻辑无副作用)可以做到逻辑等价、性能更优,且圈复杂度降到4,远低于阈值要求。
推荐实现(无副作用场景,性能更优)
private boolean isPropertyAccessed(AccessLevels readAccessLevel, Relationship relationship) { // 优先判断全权限标记,命中则直接返回,避免后续无用判断 if (readAccessLevel.isAll()) { return true; } // 严格按原代码顺序封装判断逻辑为延迟执行单元,保证判断优先级与原逻辑一致 List<Supplier<Boolean>> accessChecks = Arrays.asList( () -> readAccessLevel.isAccessed1() && relationship.getAccessed1Relationship() == ACCESSED1, () -> readAccessLevel.isAccessed2() && relationship.getAccessed2Relationship() == ACCESSED2, () -> readAccessLevel.isAccessed3() && relationship.getAccessed3Relationship() == ACCESSED3, () -> readAccessLevel.isAccessed4() && relationship.getAccessed4Relationship() == ACCESSED4, () -> readAccessLevel.isAccessed5() && relationship.getAccessed5Relationship() == ACCESSED5, () -> readAccessLevel.isAccessed6() && relationship.getAccessed6Relationship() == ACCESSED6 ); for (Supplier<Boolean> check : accessChecks) { if (check.get()) { return true; } } return false; }
实现说明
- 所有业务判断规则100%保留,判断优先级、短路逻辑和业务语义与原代码对齐
- 性能优于原代码:全权限场景下直接返回,不需要执行6组访问判断;非全权限场景下按顺序判断,命中即返回,不会执行后续多余判断
- 复杂度达标:方法内仅包含2个条件分支、1个循环分支,加基础路径总圈复杂度为4,符合阈值要求
严格等价实现(保留原代码执行顺序)
如果原代码中访问判断的方法调用存在副作用(如计数、日志、异常抛出等特殊逻辑),需要完全保留原代码的执行顺序和调用次数,可以使用以下实现,圈复杂度为10,刚好达到阈值要求:
private boolean isPropertyAccessed(AccessLevels readAccessLevel, Relationship relationship) { // 按原代码顺序先执行所有访问判断,保留原有调用逻辑 boolean isAccessed1 = readAccessLevel.isAccessed1() && relationship.getAccessed1Relationship() == ACCESSED1; boolean isAccessed2 = readAccessLevel.isAccessed2() && relationship.getAccessed2Relationship() == ACCESSED2; boolean isAccessed3 = readAccessLevel.isAccessed3() && relationship.getAccessed3Relationship() == ACCESSED3; boolean isAccessed4 = readAccessLevel.isAccessed4() && relationship.getAccessed4Relationship() == ACCESSED4; boolean isAccessed5 = readAccessLevel.isAccessed5() && relationship.getAccessed5Relationship() == ACCESSED5; boolean isAccessed6 = readAccessLevel.isAccessed6() && relationship.getAccessed6Relationship() == ACCESSED6; if (readAccessLevel.isAll()) { return true; } // 用循环遍历替代连续||判断,减少分支计数 for (boolean accessedResult : new boolean[]{isAccessed1, isAccessed2, isAccessed3, isAccessed4, isAccessed5, isAccessed6}) { if (accessedResult) { return true; } } return false; }
不推荐将6个判断拆分为独立私有方法的实现方式,虽然也能降低当前方法的圈复杂度,但会增加代码跳转成本,可读性没有上述两种方案好。
内容的提问来源于stack exchange,提问作者Valeriy K.
相关产品推荐
相关产品推荐

