8

私はいくつかの宿題に取り組んでおり、ネストされたwhileループが多すぎるなどの問題があるかどうかを知りたいと思いました。複数のwhileループをネストすることの欠点はありますか?もしそうなら、私が以下に持っているコードスニペットをどのようにリファクタリングしますか?

以下は、一度に1行ずつファイルを読み取り、いくつかの定義された区切り文字で区切られたフィールドを解析し、コンソールに出力する前に先頭の空白を削除するコードです。

// Read the file one line at a time
while (fgets(lineStr, MAXLINELENGTH, fp) != NULL)
{
    charPtr = strtok(lineStr, DELIMITERS);

    // Loop until line is parsed
    while (charPtr != NULL)
    {
        // Skip past leading whitespace
        while (isspace(*charPtr))
            charPtr++;

        puts(charPtr);
        charPtr = strtok(NULL, DELIMITERS);
    }
}
4

3 に答える 3

8

これは実際にはかなり主観的なトピックです。私の見解では、3つのネストされたwhileループに根本的な問題はありませんが、許容範囲の限界に達しています。ネストのレベルをさらに1つまたは2つ追加すると、読者が理解することを期待するのに合理的な境界を越えると思います。人間の脳は、ある時点で非常に多くの複雑さを処理することしかできません。

私の意見に反して、関数には1レベル以下のネストが必要であり、関数には約10行を超えるコードが含まれていてはならないと主張する人もいます。反対の議論は、そのようなポリシーはより断片化された、ばらばらのコードをもたらす可能性があるということです。私の親指のルールは、コードのチャンクに適した関数名を思いつかない場合、おそらくそのコードのチャンクは実際には関数として独立することを意図していないということです。

この機能を分割する方法を見ると、いくつかの明らかなオプションがあります。

  1. 最も外側の本体をwhile別の関数に抽出します。その抽出された関数は1行を処理します。名前を付けて読みやすくするのは簡単です。
  2. while空白をスキップするループを別の関数に抽出します。これも名前を付けるのが簡単で、コードが読みやすくなります。抽出された関数の名前によって空白が不要になるため、空白のコメントを削除します。それはおそらくやる価値があります。

これらのアイデアを適用した場合、コードは次のようになります。

char* skipWhitespace(char* str)
{
    while (isspace(*str))
        str++;
    return str;
}

void parseLine(char *lineStr)
{
    charPtr = strtok(lineStr, DELIMITERS);
    while (charPtr != NULL)
    {
        charPtr = skipWhitespace(charPtr);
        puts(charPtr);
        charPtr = strtok(NULL, DELIMITERS);
    }
}
......
while (fgets(lineStr, MAXLINELENGTH, fp) != NULL)
    parseLine(lineStr);

抽出されたメソッドのリファクタリングと名前付けにより、コメントが少し不要になり、削除したことに注意してください。もう1つの経験則は、コードにコメントを付けすぎる必要がある場合、おそらくまだ十分に因数分解されていないということです。

結局のところ、厳格で迅速なルールは実際にはなく、それは判断と個人的な好みに帰着します。私の見解では、質問のコードは非常に明確で読みやすいですが、リファクタリングされたバージョンは私の見解では少し明確です。

免責事項:コードの正確性やその他の点についてはコメントしません。私は単にその側面を無視しました。

于 2012-04-25T22:54:10.300 に答える
3

唯一の本当の欠点は読みやすさです。これについては、厳密で迅速なルールはありません...ただし、通常、3つを超えるネストは、作業している他の人を苛立たせます。別のポスターが言ったように、ループを別の関数に移動してネストを壊したほうがよい場合もありますが、ここにあるものは私には完全に読みやすく、それが唯一の実際のメトリックです。純粋な主観的意見:)

于 2012-04-25T22:54:12.580 に答える
0

前述のように、これは比較的主観的なものです。ただし、ループをネストする方法は、コードのパフォーマンスに直接影響を与える可能性があります。キャッシュ対応プログラミングを検討してください。つまり、プロセッサがデータの次のブロックを必要になる前にキャッシュメモリにプリフェッチ(つまり予測)できるようにコードを配置する必要があります。これにより、より多くのキャッシュヒットとより高速なメモリアクセス時間が可能になります。

これはあなたの例では特に重要ではないことに注意してください。ただし、多くのメモリアクセスを行う場合、これはパフォーマンスを大幅に増減させる可能性があります。行優先アーキテクチャで列単位の方法で多次元配列をトラバースしている場合、多くのキャッシュミスが発生する可能性があります(キャッシュミスはリアルタイムの観点から非常にコストがかかることに注意してください)。

したがって、ループのネストは必ずしも悪いわけではありませんが、特に任意の数のnループの後で、パフォーマンスに顕著な影響を与える可能性があります。

于 2012-04-25T23:01:24.137 に答える