13

if/while/for ステートメントを含む決定ステートメントの数が多いメソッドでは、循環的複雑度が高くなります。では、どうすれば改善できるでしょうか。

CCが10を超えるメソッドのCCを減らすことになっている大きなプロジェクトを処理しています。この問題を伴うメソッドはたくさんあります。以下に、私が遭遇した問題を含むコード パターン (実際のコードではない) の例をいくつか挙げます。それらを単純化できる可能性はありますか?

多くの意思決定ステートメントが発生するケースの例:

ケース 1)

if(objectA != null) //objectA is a pass in as a parameter
{
 objectB = doThisMethod();
 if(objectB != null)
 {
  objectC = doThatMethod();
  if(objectC != null)
  {
   doXXX();
  }
  else{
   doYYY();
  }
 }
 else
 {
  doZZZ();
 }
}

ケース 2)

if(a < min)
 min = a;

if(a < max)
 max = a;

if(b > 0)
 doXXX();

if(c > 0)
{
 doYYY();
}
else
{
 doZZZ();
 if(c > d)
  isTrue = false;

 for(int i=0; i<d; i++)
  s[i] = i*d;

 if(isTrue)
 {
  if(e > 1)
  {
   doALotOfStuff();
  }
 }
}

ケース 3)

// note that these String Constants are used elsewhere as diff combination,
// so you can't combine them as one
if(e.PropertyName.Equals(StringConstants.AAA) ||
e.PropertyName.Equals(StringConstants.BBB) ||
e.PropertyName.Equals(StringConstants.CCC) ||
e.PropertyName.Equals(StringConstants.DDD) ||
e.PropertyName.Equals(StringConstants.EEE) ||
e.PropertyName.Equals(StringConstants.FFF) ||
e.PropertyName.Equals(StringConstants.GGG) ||
e.PropertyName.Equals(StringConstants.HHH) ||
e.PropertyName.Equals(StringConstants.III) ||
e.PropertyName.Equals(StringConstants.JJJ) ||
e.PropertyName.Equals(StringConstants.KKK)) 
{
 doStuff();
}
4

4 に答える 4

14

ケース 1 - 小さな関数にリファクタリングするだけでこれに対処できます。たとえば、次のスニペットは関数である可能性があります。

objectC = doThatMethod();
if(objectC != null)
{
 doXXX();
}
else{
 doYYY();
}

ケース 2 - まったく同じアプローチ。else 句の内容を小さなヘルパー関数に取り出します

ケース 3 - チェックしたい文字列のリストを作成し、文字列を多くのオプションと比較する小さなヘルパー関数を作成します (linq でさらに簡略化できます)。

var stringConstants = new string[] { StringConstants.AAA, StringConstants.BBB etc };
if(stringConstants.Any((s) => e.PropertyName.Equals(s))
{
    ...
}
于 2010-12-17T09:33:37.920 に答える
9

CCを減らすには、リファクタリングReplace Conditional with Polymorphismを使用する必要があります。

条件付きコードとポリモーフィック コードの違いは、ポリモーフィック コードでは決定が実行時に行われることです。これにより、コードを変更せずに条件を追加/変更/削除する柔軟性が向上します。単体テストを使用して動作を個別にテストできるため、テスト容易性が向上します。また、条件付きコードが少なくなるため、コードが読みやすく、CC が少なくなります。

詳細については、行動設計パターンを調べてください。戦略

このような最初のケースを実行して、条件を削除し、結果として CC を削除します。さらに、コードはよりオブジェクト指向であり、読みやすく、テストも容易です。

void Main() {
    var objectA = GetObjectA();
    objectA.DoMyTask();
}

GetObjectA(){
    return If_All_Is_Well ? new ObjectA() : new EmptyObjectA();
}

class ObjectA() {
    DoMyTask() {
        var objectB = GetObjectB();
        var objectC = GetObjectC();
        objectC.DoAnotherTask();     // I am assuming that you would call the doXXX or doYYY methods on objectB or C because otherwise there is no need to create them
    }

    void GetObjectC() {
        return If_All_Is_Well_Again ? new ObjectC() : new EmptyObjectC();
    }
}

class EmptyObjectA() { // http://en.wikipedia.org/wiki/Null_Object_pattern
    DoMyTask() {
        doZZZZ();
    }
}

class ObjectC() {
    DoAnotherTask() {
        doXXX();
    }
}

class EmptyObjectB() { 
    DoAnotherTask() {
        doYYY();
    }
}

2 番目のケースでは、最初と同じように実行します。

3番目のケースでは -

var myCriteria = GetCriteria();
if(myCriteria.Contains(curretnCase))
    doStuff();

IEnumerable<Names> GetCriteria() {
   // return new list of criteria.
}
于 2010-12-17T09:32:41.867 に答える
2

私は C# プログラマーではありませんが、試してみます。

最初のケースでは、そもそもオブジェクトが null であってはならないと言います。これが避けられない場合 (通常は回避可能です)、早期復帰パターンを使用します。

if ( objectA == NULL ) {
    return;
}
// rest of code here

2 番目のケースは明らかに現実的なコードではありませんが、少なくとも次のように言いたいと思います。

if ( isTrue && e > 1 ) {
    DoStuff();
}

2 つの別々の if を使用するのではなく、

最後のケースでは、テストする文字列を配列/ベクター/マップに格納し、そのコンテナー メソッドを使用して検索を行います。

そして最後に、循環的複雑度を使用することは「良いこと」(tm) であり、私自身も使用していますが、当然ながら少し複雑にする必要がある関数がいくつかあります - ユーザー入力の検証はその例です。私が使用している CC ツール ( http://www.campwoodsw.comのソース モニター- 無料で非常に優れている) が、複雑である必要があるとわかっている関数のホワイトリストをサポートしていて、それを望んでいないことをよく望みます。国旗。

于 2010-12-17T09:38:53.547 に答える
1

ケース2の場合の最後のifは単純化できます:

 if(isTrue)
 {
  if(e > 1)
  {

で置き換えることができます

if(isTrue && (e>1))

ケース3は次のように書き直すことができます。

new string[]{StringConstants.AAA,...}
    .Contains(e.PropertyName)

文字列配列をaHashSet<String>にして、O(1)のパフォーマンスを得ることができます。

于 2010-12-17T09:35:42.223 に答える