有关认知复杂性及其计算方式的一般说明,请查看此答案:https://stackoverflow.com/a/62867219/7730554。
首先,我想说的是,我并不是想提出比 jahra 已经提供的更好的解决方案(这很棒)。我更愿意分享如何通过应用众所周知的重构技术采取安全的婴儿步骤来降低认知复杂性。最终结果当然与现有答案中已经显示的结果非常相似。
关于这个特定示例,您可以通过应用简单的重构(例如 Replace Nested Condition with Guard Clause、Consolidate Duplicate Conditional Fragments 和 Extract Method)轻松实现认知复杂性的降低。我应用了这些,如下面的代码清单所示,正如代码 cmets 中所强调的那样。
注意:现在大多数 IDE 已经将这些重构提供为 自动重构 开箱即用,在我的例子中,我使用了 IntelliJ(用于 Java),它提供了所有提到的重构,所以我不必手动进行这些。其他技术堆栈提供类似的功能,例如.Net 的 Rider 或 ReSharper,PHP 的 PHPStorm 等。
我们先计算一下原始代码的认知复杂度(每条相关语句的计算见cmets):
// Total cognitive complexity: 9
public char findDelimiter_original(String fieldseparator)
{
char delim = '\0';
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。
在下一步中,我应用了 Replace Nested Condition with Guard Clause 和 Consolidate Duplicate Conditional Fragments 重构。
注意:使用 IntelliJ Replace Nested Condition with Guard Clause 可以通过“Invert if condition”轻松实现,而 Consolidate Duplicate Conditional Fragments可以通过“Extract common part”实现从如果”来自 IntelliJ 上下文菜单。
// 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 '\0';
}
// 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,这已经很棒了,但我们仍然可以做得更好,尤其是在可读性方面。
在最后一步中,我应用了 Extract Method 重构,它在 IntelliJ 中也可用作自动重构。
// Total cognitive complexity: 2
public char findDelimiter_extractMethod(String fieldseparator)
{
// Applied "extract method" refactoring
if (hasNoSeparator(fieldseparator)) { // +1 for the if condition
return '\0';
}
// 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,而 main 方法现在的认知复杂度仅为 2。
最后我们可以用三元运算符替换最后一个 if 条件(IntelliJ 也通过“replace if else with ?”提供了它。
// Total cognitive complexity: 2
public char findDelimiter_extractMethod(String fieldseparator)
{
// Applied "extract method" refactoring
if (hasNoSeparator(fieldseparator)) { // +1 for the if condition
return '\0';
}
// Introduced ternary operator
// +1 for the ternary operator
return fieldSeparatorIsTab(fieldseparator) ? '\t' : handleUnicodeString(fieldseparator).charAt(0);
}