3

次の3つの関数を考えてみましょう。これらはすべて同じように動作し、異なるコードを使用して同じことを実現します(例はJavaScriptで記述されており、JavaScriptに適用される回答に特に関心がありますが、この質問は実際にはどの関数にも当てはまります。同様の構造を持つ言語):

// Random number from 0-9
var x = Math.floor(Math.random() * 10);

// JSHint reports a cyclomatic complexity of 3
function a() {
    if (x === 0) {
        return "First";
    } else if (x === 1 || x === 2) {
        return "Second"; 
    }
    return "Third";
}

// JSHint reports a cyclomatic complexity of 4
function b() {
    switch (x) {
    case 0:
        return "First";
    case 1:
    case 2:
        return "Second";
    default:
        return "Third";
    }
}

// JSHint reports a cyclomatic complexity of 1
function c() {
    return x === 0 ? "First" : x === 1 || x === 2 ? "Second" : "Third";
}

// All three functions return the same value
console.log(a(), b(), c());

JSComplexityツールは、3つの関数すべての複雑度が4であると報告します。これは、フォールスルーステートメントと同様に、演算子が||独立したブランチとして扱われることを意味します。caseJSHintは演算子を気にしていないようですが||、フォールスルーcaseステートメントを同じように処理します。条件演算子が完全に間違っているようです。

循環的複雑度を計算する場合、フォールスルーcaseステートメントと論理「または」演算子を独立したブランチとして扱う必要がありますか?三元条件についてはどうですか(これはもっと簡単だと思います。この場合、JSHintは明らかに間違っています)。上記の3つの関数はすべて、同じ循環的複雑度を持つ必要がありますか?

4

1 に答える 1

7

循環的複雑度は、コードを通る線形独立パスの数です。フォールスルーcaseは空虚ですが、それは明らかに別の道​​だと思います。では、問題は||新しいブランチを導入するかどうかです。

ここでは声を出して考えていますが、JavaScriptは条件文の短絡評価を実行するため、論理和から実際に2つの分岐が得られると思います。たとえば、a関数は次と同等です。

function a() {
    if (x === 0) {
        return "First";
    } else if (x === 1) {
        return "Second"; 
    } else if (x === 2) {
        return "Second";
    } else {
       return "Third";
    }
}

... 2つが同じ機能を実行しているにもかかわらず、4つのブランチがあります。(つまり、頂点ではなくエッジの線形独立性。)ただし、JSが短絡評価を行わなかった場合は、x === 1 || x === 21つのブランチを呼び出すことを検討する傾向があります。

したがって、あなたの質問に答えるには、3つの関数すべてが同じ循環的複雑度を持つ必要があると思います:4。

于 2013-03-18T15:20:08.720 に答える