Wie man mit Flag in mehreren if-else's umgeht

10

Ich sehe das oft genug in meinem Code und anderen. Es gibt nichts, was schrecklich falsch scheint, aber es ärgert mich, da es so aussieht, als ob es besser gemacht werden kann. Ich nehme an, eine case-Anweisung mag etwas sinnvoller sein, aber häufig ist variable ein Typ, der mit case-Anweisungen (je nach Sprache) nicht gut oder überhaupt nicht funktioniert.

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

Es scheint, dass es mehrere Möglichkeiten gibt, dies zu "faktorisieren", z. B. zwei Sätze von If-Elses, wobei ein Satz behandelt, wenn Flag == true ist.

Gibt es einen "guten Weg", dies zu berücksichtigen, oder wenn dieser If-else-Algorithmus auftritt, bedeutet dies normalerweise, dass Sie etwas falsch machen?

TruthOf42
quelle
6
Könnte es möglich sein, die Flag-Variable an doFooX zu übergeben, die sich mit dem Flag selbst befassen könnte?
Jean-François Côté
sicher, aber dann haben Sie nur eine Methode doFooX, die auswertet, ob das Flag wahr ist, und dann entweder doFooX1 oder doFooX2
TruthOf42
5
IMHO wird es noch klarer zu lesen sein. Dann kommt es darauf an, was doFooA und doFooA2 tun ...
Jean-François Côté
2
Warum if (Flag == true)eher schreiben als nur If (Flag)? Wenn Sie denken, dass If (Flag == true)das besser ist, warum nicht if ((Flag == true) == true)?
Keith Thompson
1
Die wichtigste Erkenntnis aus den meisten der folgenden Antworten ist, dass Einfachheit und Lesbarkeit weitaus wichtiger sind als clevere Tricks, wenn es um den logischen Ablauf und die Pflege des Codes in der Zukunft geht.
Patrick Hughes

Antworten:

18

Es könnte mit Polymorphismus behandelt werden.

factory(var, flag).doFoo();

Immer wenn Sie eine Reihe von if / else-Überprüfungen des Typs von etwas haben, können Sie die if / else-Überprüfung in einer Factory-Methode zentralisieren und dann doFoo () polymorph aufrufen. Dies könnte jedoch für eine einmalige Lösung zu viel sein.

Vielleicht könnten Sie eine Schlüssel- / Wertezuordnung erstellen, in der der Schlüssel var / flag ist und der Wert die Funktion selbst ist.

do[var, flag]();
mike30
quelle
2
+1: Tabellensuchen schlagen verschachtelte if-Anweisungen fast jedes Mal.
Kevin Cline
1
Ich möchte sagen, dass dies die beste Lösung ist.
Der Muffin-Mann
6

Mehrere verschachtelte ifs erhöhen die zyklomatische Komplexität des Codes. Bis vor kurzem galt das Vorhandensein mehrerer Exit-Punkte in einer Funktion als schlecht strukturierter Code. Solange der Code einfach und kurz ist , können Sie dies jetzt tun, sodass der Code trivial zu lesen ist:

    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;
Tulains Córdova
quelle
3

Eine andere Möglichkeit besteht darin, if und switch zu kombinieren. Dies ist Ihrer verschachtelten if-Technik nicht überlegen, kann jedoch die Anzahl doppelter Tests verringern (wenn der Switch auf eine Sprungtabelle optimiert wird).


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;
}
DwB
quelle
0

Nun, es gibt immer das ...

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

Aber ehrlich gesagt denke ich, dass der ursprüngliche Code überhaupt nicht schlecht ist.

Ross Patterson
quelle
0

Verwenden Sie Polymorphismus und ein ruleArray

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);
  }
}

Oder wie mike30vorgeschlagen: Wenn die Regelbedingungen leicht einen Schlüssel bilden können, ist eine Hashmap der beste Weg.

Matyas
quelle