【问题标题】:How can I reduce a Cognitive Complexity of its method?如何降低其方法的认知复杂性?
【发布时间】:2021-06-29 03:44:07
【问题描述】:

我有一种将罗马数字转换为常用十进制的方法。我在这里使用了一个循环和许多“如果”条件。 我的 IDE 中的 SonarLint 告诉我,此方法的认知复杂度为 33,而允许为 15。 我怎样才能减少这种情况?我不介意如何解决这个问题。期待您的推荐!

public static int roman2Decimal(String roman) {
        int decimal = 0;
        char previous = 0;

        for (int x = 0; x < roman.length(); x++) {
            if (roman.charAt(x) == 'I')
                decimal += 1;

            if (roman.charAt(x) == 'V') {
                System.out.println(previous);
                if (previous == 'I') {
                    decimal -= 2;
                }
                decimal += 5;
            }

            if (roman.charAt(x) == 'X') {
                if (previous == 'I') {
                    decimal -= 2;
                }
                decimal += 10;
            }

            if (roman.charAt(x) == 'L') {
                if (previous == 'X') {
                    decimal -= 20;
                }
                decimal += 50;
            }

            if (roman.charAt(x) == 'C') {
                if (previous == 'X') {
                    decimal -= 20;
                }
                decimal += 100;
            }

            if (roman.charAt(x) == 'D') {
                if (previous == 'C') {
                    decimal -= 200;
                }
                decimal += 500;
            }

            if (roman.charAt(x) == 'M') {
                if (previous == 'C') {
                    decimal -= 200;
                }
                decimal += 1000;
            }
            previous = roman.charAt(x);
        }
        return decimal;
    }

【问题讨论】:

  • 认知复杂度与方法长度或逻辑分支(if 语句)的嵌套有关。你最好使用switch 作为roman.charAt(x) 表达式。至少。

标签: java optimization code-complexity


【解决方案1】:

第一步是用switch 替换重复的if 语句:

public static int roman2Decimal(String roman) {
    int decimal = 0;
    char previous = 0;


    for (int x = 0; x < roman.length(); x++) {
        switch (roman.charAt(x)) {
            case 'I':
                decimal += 1;
                break;
            case 'V':
                if (previous == 'I') {
                    decimal -= 2;
                }
                decimal += 5;
                break;
            case 'X':
                if (previous == 'I') {
                    decimal -= 2;
                }
                decimal += 10;
                break;
            case 'L':
                if (previous == 'X') {
                    decimal -= 20;
                }
                decimal += 50;
                break;
            case 'C':
                if (previous == 'X') {
                    decimal -= 20;
                }
                decimal += 100;
                break;
            case 'D':
                if (previous == 'C') {
                    decimal -= 200;
                }
                decimal += 500;
                break;
            case 'M':
                if (previous == 'C') {
                    decimal -= 200;
                }
                decimal += 1000;
                break;
        }
        previous = roman.charAt(x);
    }
    return decimal;
}

如果我们进一步重构,我们可能会注意到其他重复的模式。使用枚举有助于使这种方法更加简洁:

enum RomanDigit {
    ZERO(0, null), // sentinel
    I(1, ZERO),
    V(5, I),
    X(10, I),
    L(50, X),
    C(100, X),
    D(500, C),
    M(1000, C);

    public final int inc;
    public final RomanDigit prev;

    RomanDigit(int inc, RomanDigit prev) {
        this.inc = inc;
        this.prev = prev;
    }
}

public static int roman2Decima2l(String roman) {
    int decimal = 0;
    RomanDigit previous = RomanDigit.ZERO;
    for (char c : roman.toCharArray()) {
        RomanDigit current = RomanDigit.valueOf(String.valueOf(c));
        if (previous.equals(current.prev)) {
            decimal -= 2 * previous.inc;
        }
        decimal += current.inc;
        previous = current;
    }
    return decimal;
}

【讨论】:

    【解决方案2】:

    切换案例更适合此任务,因为只有一个选项可以为真,或者如果您想坚持“如果”,那么请执行 if else,这样您就不需要检查所有选项,但只有在您找到正确的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      • 2018-09-19
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      相关资源
      最近更新 更多