简体   繁体   English

使用具有较高循环复杂性的if / switch语句来处理代码的最佳方法是什么?

[英]What is the best way to handle code with if/switch statements having high cyclomatic complexity?

I have a method that takes an input called capability id. 我有一个方法,需要一个称为功能ID的输入。 Based on the capability id, I execute the business implementations put forward in form of a switch case. 根据功能ID,我以交换案例的形式执行所提出的业务实现。 I have my functionality working, But came across a problem where the sonar report is showing high cyclomatic complexity around 12-14. 我的功能正常运行,但是遇到了一个问题,即声纳报告显示12-14岁左右的圈内复杂度很高。 The company I work for, uses a standard of 10 as the max cyclomatic complexity. 我工作的公司使用10的标准作为最大的圈复杂度。 My considerations is that, If I happen to break the code into too many block, the code readability is getting affected. 我的考虑是,如果我碰巧将代码分成太多块,则代码的可读性会受到影响。

Note:- I don't have permissions to change sonar rules. 注意:-我无权更改声纳规则。

Unfortunately, I can't share the code. 不幸的是,我无法共享代码。 The code would be in the following way though, 该代码将通过以下方式进行,

// 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
    }
}

Update: I was able to resolve my problem, with a solution I posted in below answers. 更新:通过以下答案中发布的解决方案,我能够解决我的问题。

There are multiple ways to avoid large if-else statements. 有多种避免大型if-else语句的方法。

Maybe the most common patterns are the template method pattern and the strategy pattern . 也许最常见的模式是template method patternstrategy pattern

As you haven't provided any code, it's hard to help you to lower the cyclomatic complexity, but I'm absolutely sure, there's a way to avoid those if-else -s. 由于您未提供任何代码,因此很难帮助您降低循环复杂度,但是我绝对可以肯定,有一种方法可以避免这些if-else -s。

I'd suggest you to read a bit about the topic; 我建议您阅读有关该主题的内容。 I'll provide you some sources I've found useful: 我将为您提供一些有用的资源:

  1. Using strategy to replace if else 使用策略来替代
  2. Using command pattern to replace conditional logic 使用命令模式替换条件逻辑
  3. I'd encourage you to use enums, they are more usable in conditional logic than you'd think: using enums instead of switch 我鼓励您使用枚举,它们在条件逻辑中比您想象的更有用: 使用枚举而不是switch
  4. Also it's good to know about various design patterns, maybe you can find a suitable one here 也很高兴了解各种设计模式,也许您可​​以在这里找到合适的模式

Also a readable code means it's easy to understand. 可读的代码也很容易理解。 I agree with @Erwin Bolwidt's comment, if you create more methods with good names, it will be easier to read. 我同意@Erwin Bolwidt的评论,如果您创建更多具有好名字的方法,将更易于阅读。 To read more about the topic, check the book "Clean Code" by Robert C. Martin. 要阅读有关该主题的更多信息,请查看Robert C. Martin的书“ Clean Code”。

I suggest that you refactor this switch statement (which is a code smell) using polymorphism. 我建议您使用多态来重构此switch语句(这是一种代码味道)。 A possible way to do it is something like that: 可能的方法是这样的:

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();
    }
}

More useful resources talking about the 'switch smell': 有关“开关气味”的更多有用资源:

If there is nothing wrong with your code, why make it more complex only to avoid SonarQube warnings? 如果您的代码没有错,为什么仅为了避免SonarQube警告而使其变得更复杂? You might not be allowed to change SonarQube rules, but you certainly can suppress the warning by annotating your method with the following: 可能不允许您更改SonarQube规则,但是您可以通过以下方法注释方法来抑制警告:

@SuppressWarnings("squid:MethodCyclomaticComplexity")

I have figured one way to handle the big if/switch statements. 我想出了一种处理大型if / switch语句的方法。 Based on the ideas, I got from everyone of you. 基于这些想法,我从大家中得到了启发。 I compiled into a simple solution that is easy to understand and modify, also handles the complexity part. 我将其编译成一个易于理解和修改的简单解决方案,还处理了复杂性部分。 Please find my solution below, 请在下面找到我的解决方案,

// 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM