【问题标题】:Refactor this method to reduce its Cognitive Complexity重构此方法以降低其认知复杂性
【发布时间】:2022-01-02 16:22:06
【问题描述】:

我在重构这部分代码时遇到了问题。如何降低这段代码的认知复杂度

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

【问题讨论】:

    标签: java


    【解决方案1】:
    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();
    }
    

    【讨论】:

    • 方法太多。所以为了避免这种复杂性,我必须将它转换成一些方法类型
    【解决方案2】:

    有关认知复杂性及其计算方式的一般说明,请查看此答案:https://stackoverflow.com/a/62867219/7730554

    首先,我想说的是,我并不是想提出比 jahra 已经提供的更好的解决方案(这很棒)。我更愿意分享如何通过应用众所周知的重构技术采取安全的婴儿步骤来降低认知复杂性。最终结果当然与现有答案中已经显示的结果非常相似。

    关于这个特定示例,您可以通过应用简单的重构(例如 Replace Nested Condition with Guard ClauseConsolidate Duplicate Conditional FragmentsExtract 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 ClauseConsolidate 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,而 ma​​in 方法现在的认知复杂度仅为 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-09-19
      • 1970-01-01
      • 2019-03-08
      • 2021-10-31
      • 1970-01-01
      • 2021-06-29
      • 2019-11-02
      • 2021-09-22
      • 1970-01-01
      相关资源
      最近更新 更多