如何降低其方法的认知复杂性?
How can I reduce a Cognitive Complexity of its method?
我有一种方法可以将罗马数字转换为普通小数。我在这里使用了一个循环和很多“如果”条件。
我的 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;
}
Switch case 更适合这项任务,因为只有一个选项可以为真,或者如果你想坚持“如果”,那么就做 if else,这样你就不需要检查所有选项,而只需要检查直到找到正确的为止。
第一步是将重复的 if
语句替换为 switch
:
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;
}
我有一种方法可以将罗马数字转换为普通小数。我在这里使用了一个循环和很多“如果”条件。 我的 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;
}
Switch case 更适合这项任务,因为只有一个选项可以为真,或者如果你想坚持“如果”,那么就做 if else,这样你就不需要检查所有选项,而只需要检查直到找到正确的为止。
第一步是将重复的 if
语句替换为 switch
:
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;
}