Cómo manejar la bandera en múltiples if-else

10

Parece que veo esto con bastante frecuencia en mi código y en otros. No hay nada en eso que parezca terriblemente mal, pero me molesta ya que parece que se puede hacer mejor. Supongo que una declaración de caso, podría tener un poco más de sentido, pero a menudo variable es un tipo que no funciona bien o en absoluto con declaraciones de caso (dependiendo del idioma)

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

Parece que hay varias formas de "factorizar" esto, como 2 conjuntos de if-elses, donde un conjunto se maneja cuando Flag == verdadero.

¿Hay una "buena manera" de factorizar esto, o tal vez cuando ocurre este algoritmo if-else, generalmente significa que está haciendo algo mal?

TruthOf42
fuente
66
¿podría ser posible pasar la variable Flag al doFooX que podría manejar la bandera en sí?
Jean-François Côté
seguro, pero entonces solo tienes un método doFooX, que evalúa si el indicador es verdadero y luego hace doFooX1 o doFooX2
TruthOf42
55
En mi humilde opinión, aún será más claro de leer. Entonces depende de lo que hagan doFooA y doFooA2 ...
Jean-François Côté
2
¿Por qué escribir en if (Flag == true)lugar de solo If (Flag)? Si crees que If (Flag == true)es mejor, ¿por qué no if ((Flag == true) == true)?
Keith Thompson
1
La conclusión más importante de la mayoría de las respuestas a continuación es que la simplicidad y la legibilidad son mucho más importantes que los trucos inteligentes en lo que respecta al flujo lógico y el mantenimiento del código en el futuro.
Patrick Hughes

Respuestas:

18

Se podría manejar con polimorfismo.

factory(var, flag).doFoo();

Siempre que tenga un montón de verificaciones if / else sobre el tipo de algo, puede considerar centralizar la verificación if / else en un método de fábrica, luego llamar a doFoo () polimórficamente. Pero esto podría ser excesivo para una solución única.

Tal vez podría crear un mapa de clave / valor donde la clave es var / flag, y el valor es la función misma.

do[var, flag]();
mike30
fuente
2
+1: Las búsquedas en la tabla superan las sentencias if anidadas casi siempre.
Kevin Cline
1
Quiero decir que esta es la mejor solución.
The Muffin Man
6

Múltiples ifs anidados aumentan la complejidad ciclomática del código. Hasta hace poco, tener múltiples puntos de salida en una función se consideraba un código estructurado incorrecto, pero ahora, siempre que el código sea simple y breve , puede hacerlo, haciendo que el código sea trivial para leer:

    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
fuente
3

Otra opción es combinar if y switch. Esto no es superior a su técnica anidada, pero puede reducir el número de pruebas duplicadas (si el interruptor se optimiza a una tabla de salto).


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
fuente
0

Bueno, siempre hay esto ...

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

Pero, francamente, creo que el código original no es tan malo en primer lugar.

Ross Patterson
fuente
0

Usa polimorfismo y una rulematriz

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

O como se mike30sugiere: si las condiciones de la regla pueden formar fácilmente una clave, entonces un hashmap es la mejor manera de hacerlo.

Matyas
fuente