-1

如何提高代码中的认知复杂性?

我有一个方法,它有 while 循环,在很多 IF ELSE 块中,我尝试使用 SWITCH 语句删除 IF ELSE,但根据 SONAR 立方体分析,认知复杂性没有改善。

这是我现有的代码:

while (this.moveNextDelegate(fileLineEnumerator))
{
    var line = fileLineEnumerator.Current;
    var recordType = GetRecordType(line);  // This Method returns the type of record

    if (recordType == "1")
    {
        headerId++;
        fileHeader = line; // Here fileHeader is being used in downsteam code flow - line 19
        // some custom logic - deleted
    }
    else if (recordType == "5")
    {
        batchHeader = line; // Here batchHeader is being used in downsteam code flow - line 19
        isRepeativeRecord = false;
    }
    else if (recordType == "6")
    {
            batchHeaderId =     // some custom logic - deleted
             // Here batchHeaderId is being used in downsteam code flow - line 35 
            detailId++;
            isFlag = false;
            isRepeativeRecord = true;
            // some custom logic - deleted
    }
    else if (recordType == "7" && !isFlag)
    {
        addendaId++;
        detailRecordsExist = true;
        // some custom logic - deleted
    }
    
        currentIndex++;
}
        

我使用 Switch 语句的新代码 - 但复杂性仍然没有改善

    while (this.moveNextDelegate(fileLineEnumerator))
    {
        var line = fileLineEnumerator.Current;
        var recordType = GetRecordType(line);

        switch (recordType)
        {
            case "1":
                {
                    headerId++;
                    fileHeader = line; 
                    // some custom logic - deleted
                    break;
                }

            case "2":
                {
                    batchHeader = line;
                    isRepeativeRecord = false;
                    break;
                }

            case "6": 
                {

                // some custom logic - deleted
                    break;
                }

            case "7": 
                {
                    if (!isFlag)
                    {
                // some custom logic - deleted
                    }

                    break;
                }

            case "8": 
                {
                    if (!isFlag)
                    {
                        // some custom logic - deleted
                    }

                    break;
                }
        }

        currentIndex++;
    }
4

1 回答 1

0

if/else从to语句切换switch可能是一个好主意,不要从最终代码中丢弃它,但不会降低复杂性,因为“if/else/switch”语句仍然与其他if语句一起存在于主体中。

为避免声纳复杂性,编写更简单的方法,每个方法都有一个目标,最好是测试并且有更少的逻辑要理解。

https://en.wikipedia.org/wiki/SOLID

查看您的代码,您可以提取一些方法,我进行了一些重构以降低复杂性,如下面的列表所示:

  1. 将主体代码提取到方法中
  2. 将“记录类型”正文代码提取到另一个方法
  3. 您仍然可以重构为类(小心,可能是过度工程)
private void Foo()
{
    FileEnumerator fileLineEnumerator = new FileEnumerator();

    while (this.moveNextDelegate(fileLineEnumerator))
    {
        string line = fileLineEnumerator.Current;
        ReadNextLine(line);
        currentIndex++;
    }
}

private void ReadNextLine(string line)
{
    var recordType = GetRecordType(line);

    if (recordType == "1")
    {
        this.ReadHeader(line);
    }
    else if (recordType == "5")
    {
        ReadBatchHeader(line);
    }
    else if (recordType == "6")
    {
        ReadRepeativeRecord();
    }
    else if (recordType == "7" && !this.isFlag)
    {
        ReadDetail();
    }
}

private void ReadDetail()
{
    this.addendaId++;
    this.detailRecordsExist = true;
}

private void ReadRepeativeRecord()
{
    this.batchHeaderId = this.detailId++;
    this.isFlag = false;
    this.isRepeativeRecord = true;
}

private void ReadBatchHeader(string line)
{
    this.batchHeader = line;
    this.isRepeativeRecord = false;
}

private void ReadHeader(string line)
{
    this.headerId++;
    this.fileHeader = line;
}

看起来你正在写一个阅读器,所以如果你有很多阅读器/步骤,比如阅读文件的页眉、正文、页脚,带有详细信息和递归内容,你可以将每个片段分隔在一个单独的类中,比如HeaderReader, BodyReader, DetailReader, 但这可以是过度工程,因此您将决定是否值得。

public class ReadState
{
    public RecordType RecordType { get; set; }

    public string Line { get; set; }
}

public class ReadResult
{
    public int HeaderId { get; set; }
}

public class BodyReader : IYourCustomFileFragmentReaderInterface
{
    public bool Test(ReadState state)
    {
        // check if is header
        return state.RecordType == RecordType.Body;
    }

    public ReadResult Read(ReadResult result, ReadState state)
    {
        // write state
        result.HeaderId = int.Parse(state.Line);
        return result;
    }
}

使用单独的阅读器,您可以将列表分组IYourCustomFileFragmentReaderInterface,调用Test(),如果为真,则调用该Read方法。

于 2021-08-15T21:31:33.223 回答