我在重构这部分代码时遇到问题。如何降低此代码的认知复杂性
if (fieldseparator != null && !fieldseparator.isEmpty()) {
if (fieldseparator.equals("\t")) {
delim = 't';
} else {
// handling unicode separator
Integer i = Ints.tryParse(fieldseparator);
if (i != null) {
fieldseparator = String.valueOf(Character.toChars(i));
delim = fieldseparator.charAt(0);
} else {
delim = fieldseparator.charAt(0);
}
}
}
public static Character getDelim(String fieldseparator, Character defaultDelim) {
if (isNotEmpty(fieldseparator)) {
return fieldseparator.equals("\t") ? 't' : getFromUnicode(fieldseparator);
}
return defaultDelim;
}
private static Character getFromUnicode(String fieldseparator) {
Integer i = Ints.tryParse(fieldseparator);
return i != null ? String.valueOf(Character.toChars(i)).charAt(0) : fieldseparator.charAt(0);
}
private static boolean isNotEmpty(String fieldseparator) {
return fieldseparator != null && !fieldseparator.isEmpty();
}
有关认知复杂性及其计算方式的一般解释,请查看此答案:https://stackoverflow.com/a/62867219/7730554。
首先,我想声明的是,我并没有试图提出比jahra已经提供的更好的解决方案(这很棒(。我更想分享如何通过应用众所周知的重构技术采取安全的婴儿步骤来降低认知复杂性。最终结果当然与现有答案中已经显示的结果非常相似。
关于这个特定示例,您可以通过应用简单的重构(例如用保护子句替换嵌套条件、合并重复条件片段和提取方法(来轻松降低认知复杂性。我应用了这些代码,如代码注释中强调的那样,如以下代码清单所示。
注意:如今,大多数 IDE 已经将这些重构作为开箱即用的自动重构提供,就我而言,我使用了 IntelliJ(用于 Java(,它提供了所有提到的重构,所以我不必手动进行这些重构。其他技术堆栈提供类似的功能,例如 .Net 的 Rider 或 ReSharper,PHP 的 PHPStorm 等。
我们先来计算一下原始代码的认知复杂度(见注释后面各相关语句的计算(:
// Total cognitive complexity: 9
public char findDelimiter_original(String fieldseparator)
{
char delim = ' ';
if (fieldseparator != null // +1 for the if condition
&& !fieldseparator.isEmpty()) { // +1 for the binary operator
if (fieldseparator.equals("\t")) { // +2 for the nested if (nesting = 1)
delim = 't';
} else { // +1 for else
// handling unicode separator
Integer i = Ints.tryParse(fieldseparator);
if (i != null) { // +3 for the double nested if (nesting = 2)
fieldseparator = String.valueOf(Character.toChars(i));
delim = fieldseparator.charAt(0);
} else { // +1 for the else
delim = fieldseparator.charAt(0);
}
}
}
return delim;
}
因此,原始代码给我们留下了9的认知复杂度。
在下一步中,我应用了">用保护子句替换嵌套条件"和"合并重复条件片段">重构。
注意:使用 IntelliJ 用保护子句替换嵌套条件可以通过"反转 if 条件"轻松实现,而合并重复的条件片段可以通过 IntelliJ 上下文菜单中的"从 if 中提取公共部分"来实现。
// Total cognitive complexity: 4
public char findDelimiter_guardClauses(String fieldseparator)
{
// Applied "guard clause" refactoring by inverting if
if (fieldseparator == null // +1 for the if condition
|| fieldseparator.isEmpty()) { // +1 for the binary operator
return ' ';
}
// Applied "guard clause" refactoring by inverting if
if (fieldseparator.equals("\t")) { // +1 the if condition
return 't';
}
// Applied "consolidate duplicate conditional fragments" refactoring
// handling unicode separator
Integer i = Ints.tryParse(fieldseparator);
if (i != null) { // +1
fieldseparator = String.valueOf(Character.toChars(i));
}
return fieldseparator.charAt(0);
}
现在,这给我们留下了4的认知复杂性降低,这已经很棒了,但我们仍然可以做得更好,特别是在可读性方面。
在最后一步中,我应用了提取方法重构,该重构在 IntelliJ 中也可用作自动重构。
// Total cognitive complexity: 2
public char findDelimiter_extractMethod(String fieldseparator)
{
// Applied "extract method" refactoring
if (hasNoSeparator(fieldseparator)) { // +1 for the if condition
return ' ';
}
// Applied "extract method" refactoring
if (fieldSeparatorIsTab(fieldseparator)) { // +1 for the if condition
return 't';
}
// Applied "extract method" refactoring
return handleUnicodeString(fieldseparator).charAt(0);
}
// Total complexity: 1
private String handleUnicodeString(String fieldseparator) {
Integer i = Ints.tryParse(fieldseparator);
if (i != null) { // +1 for the if condition
fieldseparator = String.valueOf(Character.toChars(i));
}
return fieldseparator;
}
// Total cognitive complexity: 0
private boolean fieldSeparatorIsTab(String fieldseparator) {
return fieldseparator.equals("\t");
}
// Total cognitive complexity: 1
private boolean hasNoSeparator(String fieldseparator) {
return fieldseparator == null || fieldseparator.isEmpty(); // +1 for the binary operator
}
整体代码(包括提取的私有方法(的整体认知复杂度仍然为 4,而主方法现在只有 2 的认知复杂度。
最后,我们可以用三元运算符替换最后一个if条件(IntelliJ也通过"替换ifelse与?"提供(。
// Total cognitive complexity: 2
public char findDelimiter_extractMethod(String fieldseparator)
{
// Applied "extract method" refactoring
if (hasNoSeparator(fieldseparator)) { // +1 for the if condition
return ' ';
}
// Introduced ternary operator
// +1 for the ternary operator
return fieldSeparatorIsTab(fieldseparator) ? 't' : handleUnicodeString(fieldseparator).charAt(0);
}