2008-12-03 11 views
23

Esto está relacionado con un capítulo del beautiful code. Y en ese capítulo leí sobre los ifs anidados.Reemplazar declaraciones anidadas si

El autor estaba hablando de if profundamente anidados como orginator de errores y menos legible. Y él estaba hablando de reemplazar ifs anidados con declaraciones de casos y tablas de decisiones.

¿Alguien puede ilustrar cómo eliminar los if anidados con mayúsculas y minúsculas (mayúsculas y minúsculas) y tablas de decisiones?

Respuesta

18

Bueno, no es una respuesta directa a su pregunta, ya que específicamente pregunta acerca de las declaraciones de cambio/caso, pero aquí hay una pregunta similar.

Invert “if” statement to reduce nesting

Esto habla de la sustitución anidada si de guardia con estados de cuenta, que devuelven temprana, en lugar de comprobar progresivamente más y más cosas antes de decidirse por un valor de retorno.

10

Un ejemplo que siempre trato de hacer es reemplazar en gran medida anidado si es así (en realidad éste no es demasiado malo, pero los he visto hasta 8 o 9 niveles de profundidad en la naturaleza):

if (i == 1) { 
    // action 1 
} else { 
    if (i == 2) { 
     // action 2 
    } else { 
     if (i == 3) { 
      // action 3 
     } else { 
      // action 4 
     } 
    } 
} 

con esto:

switch (i) { 
    case 1: 
     // action 1 
     break; 
    case 2: 
     // action 2 
     break; 
    case 3: 
     // action 3 
     break; 
    default: 
     // action 4 
     break; 
} 

también trato de mantener las acciones lo más pequeño posible (las llamadas a funciones son las mejores para esto) para mantener la sentencia switch comprimido (por lo que no tiene que ir por delante a cuatro páginas ver el final de esto).

Las tablas de decisiones, creo, simplemente están configurando indicadores que indican qué acciones deben tomarse más adelante. La sección "más adelante" es una secuencia simple de acciones basadas en esos indicadores. Podría estar equivocado (no será la primera ni la última vez :-).

Un ejemplo podría ser (la fase de establecimiento de bandera puede ser complicado si ya de sus acciones son muy simples):

switch (i) { 
    case 1: 
     outmsg = "no paper"; 
     genmsg = true; 
     mailmsg = true; 
     phonemsg = false; 
     break; 
    case 2: 
     outmsg = "no ink"; 
     genmsg = true; 
     mailmsg = true; 
     phonemsg = false; 
     break; 
    default: 
     outmsg = "unknown problem"; 
     genmsg = true; 
     mailmsg = true; 
     phonemsg = true; 
     break; 
} 

if (genmsg) 
    // Send message to screen. 
if (mailmsg) 
    // Send message to operators email address. 
if (phonemsg) 
    // Hassle operators mobile phone. 
+1

Porque "else if" es malo, y debe escribirse como "else {if ...}"? Pero tienes razón al usar un interruptor para ifs simples como este. – JeeBee

6

hacer que la condición en booleanos y luego escribir la expresión booleana para cada caso.

Si el código fue:

if (condition1) 
{ 
    do1 
} 
else 
{ 
    if (condition2) 
    { 
     do2 
    } 
    else (condition3) 
    { 
     do3; 

    } 
} 

Uno puede escribir como:

bool cond1=condition1; 
bool cond2=condition2; 
bool cond3=condition3; 

if (cond1) {do1;} 
if (!cond1 and cond2) {do2;} 
if (!cond1 and cond3) {do2;} 
+0

Esto se pone muy feo cuando hay muchas condiciones. Además, la legibilidad se pierde porque las condiciones reales están ocultas detrás de los valores booleanos. –

+0

@DanielBecroft Realmente lo veo de la manera opuesta. Estoy de acuerdo con [el enfoque de Jeff Atwood de evitar comentarios] (http://blog.codinghorror.com/coding-without-comments/), y para hacer eso, le das a esa variable booleana un nombre significativo, y eso * realzará * legibilidad ... Dicho esto, este enfoque presentado aquí no es una bala de plata, sin embargo. ¿Qué sucede si no quiere calcular innecesariamente las condiciones? – Mazyod

+0

De acuerdo con @Mazyod La desventaja de arriba es que las condiciones se calculan innecesariamente. En Scala, un vago val ayuda allí. – khivi

-1

Otro ejemplo algunos idiomas permiten que este es

  switch true{ 
      case i==0 
       //action 
      break 

      case j==2 
      //action 
      break 

      case i>j 
      //action 
      break 
      } 
8

¿Qué pasaría si encadenados?

Reemplazar

if (condition1) 
{ 
    do1 
} 
else 
{ 
    if (condition2) 
    { 
     do2 
    } 
    else (condition3) 
    { 
     do3; 

    } 
} 

con

if (condition1) { 
    do1; 
} else if (condition2) { 
    do2; 
} else if (condition3) { 
    do3; 
} 

Esto es muy parecido sentencia switch para condiciones complejas.

0

Si y las declaraciones de interruptor no son puramente OO. Son una lógica de procedimiento condicional, pero ¡haz un muy buen trabajo! Si desea eliminar estas declaraciones para un enfoque más OO, combine the 'State' and 'Descriptor' patterns.

+1

pones "no solo OO" como si fuera algo malo! – Javier

+0

Eso es como * soooooo * 1986. Debería decirle a la gente que su código no es lo suficientemente funcional en estos días. –

+0

jaja, acabo de leer el artículo recientemente y pensé que una respuesta dirigida puede ser apropiada –

1

Las tablas de decisión son donde almacenan la lógica condicional en una estructura de datos en lugar de dentro del código.

Así que en lugar de esto (usando @ ejemplo de Pax):

if (i == 1) { 
    // action 1 
} else { 
    if (i == 2) { 
     // action 2 
    } else { 
     if (i == 3) { 
      // action 3 
     } else { 
      // action 4 
     } 
    } 
} 

que hacer algo como esto:

void action1() 
{ 
    // action 1 
} 

void action2() 
{ 
    // action 2 
} 

void action3() 
{ 
    // action 3 
} 

void action4() 
{ 
    // action 4 
} 

#define NUM_ACTIONS 4 

// Create array of function pointers for each allowed value of i 
void (*actions[NUM_ACTIONS])() = { NULL, action1, action2, action3 } 

// And now in the body of a function somewhere... 
if ((i < NUM_ACTIONS) && actions[i]) 
    actions[i](); 
else 
    action4(); 

Si las posibilidades de i no son números enteros números bajos, entonces podría crear una tabla de búsqueda en lugar de acceder directamente al i elemento th de la matriz actions.

Esta técnica se vuelve mucho más útil que las declaraciones anotadas if so switch cuando se tiene una decisión sobre docenas de valores posibles.

0

Nested si son equivalentes al operador lógico Y

if (condition1) 
{ 
    if (function(2)) 
    { 
     if (condition3) 
     { 
      // do something 
     } 
    } 
} 

código equivalente:

if (condition1 && function(2) && condition3) 
{ 
    // do something 
} 

En ambos casos, cuando una expresión evalúa falsa, no se evalúa la expresión posterior. Por ejemplo, si la condición1 es falsa, la función() no se invocará y la condición3 no se evaluará.

+0

No es :) porque 'function (2)' no se ejecutará si 'condition1' es falso, en el segundo ejemplo las 3 funciones se ejecutará, lo que puede afectar el rendimiento. – Coder

+0

No, @PHPLover - PHP utiliza la evaluación diferida (a veces llamada evaluación de cortocircuito), por lo que si la primera condición en un AND lógico es falsa, no intentará evaluar ninguna de las demás condiciones. Del mismo modo, si estuvieras haciendo un quirófano y la primera condición fuera verdadera, no evaluaría el segundo. –

+0

aún no son equivalentes, acabo de probar, si el segundo argumento tiene un error, se mostrará un error, lo que significa que la instrucción if aún ejecuta todos los argumentos. – Coder

2

Puede simplemente romper una vez que una parte de la validación falló, por ejemplo.

function validate(){ 
    if(b=="" || b==null){ 
     alert("Please enter your city"); 
     return false; 
    } 

    if(a=="" || a==null){ 
     alert("Please enter your address"); 
     return false; 
    } 
    return true; 
} 
Cuestiones relacionadas