複数のif-elseでフラグを処理する方法


10

私のコードや他の人には、これが頻繁に見られるようです。それについてひどく間違っているように見えることについては何もありませんが、それはより良くできるように見えるので私を困らせます。Caseステートメントはもう少し理にかなっていると思いますが、多くの場合、変数はCaseステートメントではうまく機能しないか、まったく機能しないタイプです(言語によって異なります)。

If variable == A
    if (Flag == true)
        doFooA()
    else
        doFooA2

else if variable == B
    if (Flag == true)
        doFooB()
    else
        doFooB2
else if variable == C
    if (Flag == true)
        doFooC()
    else
        doFooC2

これを「因数分解」する方法は複数あるようです。たとえば、if-elsesの2つのセットで、1つのセットがFlag == trueのときに処理します。

これを因数分解する「良い方法」はありますか、またはこのif-elseアルゴリズムが発生した場合、通常は何か間違っていることを意味していますか?


6
フラグ自体を処理できるdoFooXにFlag変数を渡すことは可能でしょうか?
ジャン=フランソワ・コテ

フラグが、その後真であるとかどうかわからしかし、あなただけの方法doFooX、と評価を持っているのいずれかdoFooX1またはdoFooX2
TruthOf42

5
私見、それでも読みやすくなります。次に、doFooAとdoFooA2の動作に依存します... –Jean
-FrançoisCôté

2
なぜif (Flag == true)ただ書くのではなく書くのIf (Flag)ですか?それIf (Flag == true)が良いと思うなら、どうif ((Flag == true) == true)ですか?
キーストンプソン

1
以下の回答のほとんどから最も重要なことは、論理フローとコードを将来にわたって維持する場合、シンプルさと読みやすさが巧妙なトリックよりもはるかに重要であることです。
Patrick Hughes

回答:


18

ポリモーフィズムで処理できます。

factory(var, flag).doFoo();

何かのタイプに関するif / elseチェックがたくさんある場合は常に、if / elseチェックをファクトリメソッドに集中化してから、doFoo()をポリモーフィックに呼び出すことを検討してください。しかし、これは1回限りのソリューションではやり過ぎになる可能性があります。

おそらく、キーがvar / flagで、値が関数自体であるキー/値マップを作成できます。

do[var, flag]();

2
+1:テーブルルックアップは、ネストされたifステートメントをほぼ毎回上回ります。
kevin cline 2013年

1
これが最良の解決策だと言いたいです。
マフィンマン

6

複数のネストされたifは、コードの循環的複雑さを増加させます。最近まで、関数に複数の出口点があることは悪い構造化コードと見なされていましたが、今では、コードが単純で短い限り、そうすることができ、コードを読むのは簡単です。

    if (variable == A && Flag) {
        doFooA();
        return;
    }

    if (variable == A) {
        doFooA2();
        return;
    }

    if (variable == B && Flag){
        doFooB();
        return;
    }

    if (variable == B){
        doFooB2();
        return;
    }

    if (variable == C && Flag){
         doFooC();
         return;
    }

    if (variable == C){
         doFooC2();
    }

    return;

3

別のオプションは、ifとswitchを組み合わせることです。これは、ネストされたif手法よりも優れているわけではありませんが、重複するテストの数を減らすことができます(スイッチがジャンプテーブルに最適化されている場合)。


if (flag)
{
    switch (variable)
    {
        case A:
           ... blah
           break;

        case B:
           ... blah
           break;

        case C:
           ... blah
           break;

        default:
           ... log an error.
           ... maybe do a default action.
           break;
    }
}
else // flag == false
{
    switch (variable)
    {
        case A:
           ... blah
           break;

        case B:
           ... blah
           break;

        case C:
           ... blah
           break;

        default:
           ... log an error.
           ... maybe do a default action.
           break;
}

0

まあ、これはいつもあります...

if variable == A && Flag
    doFooA()
else if variable == A 
    doFooA2    
else if variable == B && Flag
    doFooB()
else if variable == B
    doFooB2
else if variable == C && Flag
     doFooC()
else if variable == C
     doFooC2

しかし、率直に言って、元のコードはそもそも悪くないわけではないと思います。


0

ポリモーフィズムとrule配列を使用する

interface IRule() {
  boolean applicable(args...);
  obj apply(args...);
}

static final Array<IRule> rules = [new MeaningfulNameRule1(), new MeaningfulNameRule2(), ...];

/* where */
class MeaningfulNameRuleX extends IRule{ /* */ }

/* In your method */

for (rule in rules) {
  if (rule.applicable(a,b,c)){
    return rule.apply(e,f,g);
  }
}

または、mike30提案されているとおり:ルール条件でキーを簡単に作成できる場合は、ハッシュマップが最善の方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.