代码之家  ›  专栏  ›  技术社区  ›  daemon54

使用具有高圈复杂度的if/switch语句处理代码的最佳方法是什么?

  •  1
  • daemon54  · 技术社区  · 8 年前

    我有一个方法,它接受一个称为能力id的输入。根据能力id,我执行以交换案例形式提出的业务实现。我的功能正常,但遇到了一个问题,即声纳报告显示12-14之间的圈复杂度较高。我所在的公司使用10作为最大圈复杂度的标准。我的考虑是,如果我碰巧把代码分成太多块,代码的可读性就会受到影响。

    注:- 我没有更改声纳规则的权限。

    很遗憾,我无法共享代码。不过,代码如下:,

    // Dependency Injected
    private someService;
    
    public void processCapability(..., String capabilityId) {
        switch (capabilityId) {
            case ORDER_DISPENSED_WITH_SOURCE1:
                someService.doDispense1();
            case ORDER_DISPENSED_WITH_SOURCE2:
                someService.doDispense2();
            case ORDER_REJECTED:
                someService.doReject();
            case ORDER_CANCEL:
                someService.doCancel();
            case ORDER_PURGE:
                someService.doPurge();
                ...
                default: throw exception
        }
    }
    

    更新: 我能够解决我的问题,我在下面的答案中发布了一个解决方案。

    4 回复  |  直到 8 年前
        1
  •  1
  •   abbath    8 年前

    有多种方法可以避免 if-else 声明。

    也许最常见的模式是 template method pattern strategy pattern .

    由于您没有提供任何代码,很难帮助您降低圈复杂度,但我绝对肯定,有一种方法可以避免这些问题 否则 -第条。

    我建议你读一点关于这个话题的东西;我将向您提供一些我发现有用的资源:

    1. Using strategy to replace if else
    2. Using command pattern to replace conditional logic
    3. 我鼓励您使用枚举,它们在条件逻辑中比您想象的更有用: using enums instead of switch
    4. 此外,了解各种设计模式也很好,也许你可以找到一种合适的模式 here

    可读的代码也意味着它很容易理解。我同意@Erwin Bolwidt的评论,如果你用好的名字创建更多的方法,它会更容易阅读。要了解更多关于这个主题的信息,请查阅Robert C.Martin的书“Clean Code”。

        2
  •  1
  •   Spotted    8 年前

    我建议您使用多态性重构这个switch语句(这是一种代码味道)。一种可能的方法是这样的:

    public interface Order {
        void processCapability(...);
    }
    
    public final class RejectedOrder implements Order {
        private final SomeService someService;
    
        public RejectedOrder(SomeService someService) {
            this.someService = someService;
        }
    
        @Override
        public void processCapability(...) {
            someService.doReject();
        }
    }
    
    public final class CancelledOrder implements Order {
        private final SomeService someService;
    
        public RejectedOrder(SomeService someService) {
            this.someService = someService;
        }
    
        @Override
        public void processCapability(...) {
            someService.doCancel();
        }
    }
    

    关于“开关气味”的更多有用资源:

        3
  •  0
  •   Bouke    8 年前

    如果您的代码没有任何错误,为什么只为了避免SonarQube警告而使其更复杂?您可能不被允许更改SonarQube规则,但您可以通过以下方式注释您的方法来抑制警告:

    @SuppressWarnings("squid:MethodCyclomaticComplexity")
    
        4
  •  0
  •   daemon54    8 年前

    // Dependency Injected
    private someService;
    
    public void processCapability(..., String capabilityId) {
    
      Boolean isCapabilityProcessed = processDispenseCapabilities(...) || processUpdateCapabilities(..);
    
      if(isCapabilityProcessed) {
        throw exception("Invalid Capability");
      }
    }
    
    private Boolean processDispenseCapabilities(..,String capabilityId) {
    
      Boolean result = false;
    
      switch (capabilityId) {
            case ORDER_DISPENSED_WITH_SOURCE1:
                someService.doDispense1();
                result = true;
            case ORDER_DISPENSED_WITH_SOURCE2:
                someService.doDispense2();
                result = true;
            case ORDER_REJECTED:
                someService.doReject();
                result = true;
                ...
            default: //do nothing
        }
    
      return result;
    }
    
    private Boolean processUpdateCapabilities(..,String capabilityId) {
      Boolean result = false;
    
        switch (capabilityId) {
            case ORDER_CANCEL:
                someService.doCancel();
                result = true;
            case ORDER_PURGE:
                someService.doPurge();
                result = true;
                ...
            default: //do nothing
        }
    
      return result;
    }