Comment gérer l'indicateur dans plusieurs if-else

10

Je semble voir cela assez souvent dans mon code et dans d'autres. Il n'y a rien à ce sujet qui semble horriblement mal, mais cela m'énerve car il semble que cela peut être mieux fait. Je suppose qu'une déclaration de cas peut avoir un peu plus de sens, mais souvent la variable est un type qui ne fonctionne pas bien ou pas du tout avec les déclarations de cas (selon la langue)

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

Il semble qu'il existe plusieurs façons de «factoriser» cela, comme 2 ensembles de if-elses, où un ensemble gère lorsque Flag == true.

Existe-t-il un "bon moyen" de prendre cela en compte, ou peut-être que lorsque cet algorithme if-else se produit, cela signifie généralement que vous faites quelque chose de mal?

TruthOf42
la source
6
pourrait-il être possible de passer la variable Flag au doFooX qui pourrait gérer le drapeau lui-même?
Jean-François Côté
bien sûr, mais vous avez juste une méthode doFooX, qui évalue si le drapeau est vrai et puis fait doFooX1 ou doFooX2
TruthOf42
5
À mon humble avis, il sera encore plus clair à lire. Ensuite, cela dépend de ce que font doFooA et doFooA2 ...
Jean-François Côté
2
Pourquoi écrire if (Flag == true)plutôt que juste If (Flag)? Si vous pensez que If (Flag == true)c'est mieux, pourquoi pas if ((Flag == true) == true)?
Keith Thompson
1
La conclusion la plus importante de la plupart des réponses ci-dessous est que la simplicité et la lisibilité sont bien plus importantes que les astuces intelligentes en ce qui concerne le flux logique et la maintenance du code dans le futur.
Patrick Hughes

Réponses:

18

Il pourrait être manipulé avec polymorphisme.

factory(var, flag).doFoo();

Chaque fois que vous avez un tas de vérifications if / else sur le type de quelque chose, vous pouvez envisager de centraliser la vérification if / else dans une méthode d'usine, puis d'appeler doFoo () de manière polymorphe. Mais cela pourrait être excessif pour une solution unique.

Vous pouvez peut-être créer une carte clé / valeur où la clé est var / flag et la valeur est la fonction elle-même.

do[var, flag]();
mike30
la source
2
+1: Les recherches de table battent presque chaque fois les instructions if imbriquées.
kevin cline
1
Je veux dire que c'est la meilleure solution.
The Muffin Man
6

Plusieurs if imbriqués augmentent la complexité cyclomatique du code. Jusqu'à récemment, avoir plusieurs points de sortie dans une fonction était considéré comme un mauvais code structuré, mais maintenant, tant que le code est simple et court , vous pouvez le faire, ce qui rend le code trivial à lire:

    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
la source
3

une autre option consiste à combiner if et basculer. Ce n'est pas supérieur à votre technique imbriquée si, mais peut réduire le nombre de tests en double (si le commutateur est optimisé pour une table de saut).


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
la source
0

Eh bien, il y a toujours ça ...

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

Mais franchement, je pense que le code d'origine n'est pas à moitié mauvais en premier lieu.

Ross Patterson
la source
0

Utiliser le polymorphisme et un ruletableau

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

Ou comme mike30suggéré: si les conditions de la règle peuvent facilement former une clé, une carte de hachage est la meilleure solution.

Matyas
la source