【问题标题】:Reduce complexity of 14 for a method将方法的复杂度降低 14
【发布时间】:2016-07-21 05:35:30
【问题描述】:

Pmd 告诉我这个方法 (thirdRowsValidation) 的复杂度为 14,但我无法找到减少代码的模式。

indexBookngEnd, indexTravelStart ...所有这些变量都是来自另一个循环迭代中的其他数组的索引(csv文件列的标题) - Ref1

public void thirdRowsValidation(String thirdRowCsv) {
        String[] lines1 = thirdRowCsv.split(",");
        for (int i = 0; i < lines1.length; i++) {

            if (indexBookngEnd == i && "".equals(temporalValidateBookngEnd)) {
                temporalValidateBookngEnd = (" to " + lines1[i] + "\n");

            }
            if (indexBookngStart == i
                    && !("".equals(temporalValidateBookngEnd))) {
                finalOutput.append("Then it should have booking window ");

                indexBookngStart = -1;

            }

            if (indexTravelEnd == i && "".equals(temporalValidateTravelEnd)) {
                temporalValidateTravelEnd = (" to " + lines1[i] + "\n");

            }

            if (indexTravelStart == i
                    && !("".equals(temporalValidateTravelEnd))) {

                finalOutput.append("Then it should have travel window ");

                String idHeaderColumn = String.format("%1$-" + 5 + "s", "id");
                String typeHEaderColumn = String.format("%1$-" + 50 + "s","type");
                finalOutput.append("| ");
                finalOutput.append(idHeaderColumn);

                indexTravelStart = -1;
            }

            if (indexPackageDescription == i) {
                temporalPackages = String.format("%1$-" + 50 + "s", lines1[i]);

            }

            if (indexPackageCode == i
                    && !(lines1[i].matches("[+-]?\\d*(\\.\\d+)?"))
                    && indexTravelStart == -1) {

                finalOutput.append("| ");


            }

        }

    }

参考1:

public void secondRowValidation(String secondRowCsv) {

        String[] lines1 = secondRowCsv.split(",");
        for (int i = 0; i < lines1.length; i++) {

            if ("Bookng start".equalsIgnoreCase(lines1[i])) {
                indexBookngStart = i;
            }
            if ("Bookng end".equalsIgnoreCase(lines1[i])) {
                indexBookngEnd = i;
            }

从\n 开始的数组,之后的","

public String getStoryFromCsv(String convert) {
        String[] lines = convert.split("(\n)");
        for (int j = 0; j < lines.length; j++) {

            arrayPerRow = lines[j];
            if (j == 0) { // get marketing type and number
                firstRowValidation(arrayPerRow);
            }
            if (j == 1) { // get headers
                secondRowValidation(arrayPerRow);
            }
            if (j > 1) { // get info and append according to headers
                thirdRowsValidation(arrayPerRow);
            }

        }

所以我拥有的是: - 方法 thirdRowsValidation() 的 NPath 复杂度为 649 - 方法“thirdRowsValidation”的圈复杂度为 14。

最后,我收到这样的文字,只是为了让你们有一个想法:

Then it should have booking window 8/8/16 to 10/8/16
Then it should have travel window 11/6/16 to 12/25/16
And it should have online packages:
| id    | type                                              |
| 34534 | aaa Pkg                                           |
| D434E | MKW Pkg + asdasdasdasdasdasdas                    |
| F382K | sds Pkg + Ddding                                  |
| X582F | OYL Pkg + Deluxe Dining                           |

【问题讨论】:

  • 您应该首先将循环的内容提取到单独的方法中。这降低了复杂性。然后,鉴于您似乎有相当多的字段或全局变量,可能会通过将该状态移动到单独的对象中进行一些重构,从而使进一步的重构更容易一些,因为您可以移动该状态对象。但这些只是猜测,所以从你的 IntelliJ 建议开始:-)
  • 我明白...这就是我在这里做的例子... if (j == 0) { firstRowValidation(arrayPerRow); } 但正如您所见,需要两个我无法更改的主循环
  • 但是您可以将第 4 行到最后但第三行的所有内容移动到一个方法中,这样您的 thirdRowsValidation 将只有 for 循环,然后为其中的每个调用一个方法is.
  • 我不太明白..你能用代码解释一下 ifs 是怎么回事吗?

标签: java pmd cyclomatic-complexity


【解决方案1】:

该方法的复杂性如此之高,因为它做了很多不同的事情。尝试每种方法做一件事。

public String getStoryFromCsv(String csv) {
    StringBuilder story = new StringBuilder();
    String[] lines = csv.split("\n”);
    appendBookingWindowValidation(story, lines[0]);
    appendTravelWindowValidation(story, lines[1]);
    appendOnlinePackageValidation(story, lines);
    return story.toString();
}

private void appendBookingWindowValidation(StringBuilder story, String firstLine) {
    story.append("Then it should have booking window ");
    // extract start and end date from 'firstLine'
    // and append them to the story
}

private void appendTravelWindowValidation(StringBuilder story, String secondLine) {
    story.append("Then it should have travel window ");
    // extract start and end date from 'secondLine'
    // and append them to the story
}

private void appendOnlinePackageValidation(StringBuilder story, String[] lines) {
    story.append("And it should have online packages:\n")
         .append("| id    | type                                              |\n");
    for (int i = 2 ; i < lines.length; i++) {
      // create and append a row of the online packages table
   }
}

尝试将方法所需的所有内容作为其参数之一传递。方法不应依赖于在不同方法中设置的字段的值。这降低了复杂性,也使代码更易于阅读、理解和测试。

如果一个方法或类具有很高的复杂性,那么这通常意味着它试图一次做太多不同的事情。退后一步,尝试识别它所做的不同事情并分别实施它们。这将自动生成低复杂度的代码。

将内部循环提取到新方法中通常是一种快速的技巧,它有助于降低单个方法的复杂性,但不会降低整个类的复杂性。

【讨论】:

    【解决方案2】:

    您可以首先将for-loop 的内部逻辑移动到一个单独的方法中:

    public void thirdRowsValidation(String thirdRowCsv) {
        String[] lines1 = thirdRowCsv.split(",");
        for (int i = 0; i < lines1.length; i++) {
          doSomethingWithTheRow(i, lines[i]);
        }
    }
    

    doSomethingWithTheRow() 方法中,您的内部代码将驻留在:

    doSomethingWithTheRow(int i, String row) {
        if (indexBookngEnd == i && "".equals(temporalValidateBookngEnd)) {
            temporalValidateBookngEnd = (" to " + row + "\n");
    
        }
        if (indexBookngStart == i
                    && !("".equals(temporalValidateBookngEnd))) {
        ...
    

    不确定这是否会将复杂性降低到您认为可以接受的水平,但这是第一次开始。此外,这是 Bob 大叔定义的清洁代码原则。你有一些小方法,做一件事(该方法现在只提取单行,然后调用其他方法对该行做一些事情),而且很短。即SRP(单一职责原则)和KISS(保持简单,愚蠢)原则。

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-01
      相关资源
      最近更新 更多