La mejor manera de formatear una declaración if con múltiples condiciones

88

Si desea que se ejecute algún código en función de dos o más condiciones, ¿cuál es la mejor manera de formatear esa declaración if?

primer ejemplo: -

if(ConditionOne && ConditionTwo && ConditionThree)
{
   Code to execute
}

Segundo ejemplo: -

if(ConditionOne)
{
   if(ConditionTwo )
   {
     if(ConditionThree)
     {
       Code to execute
     }
   }
}

que es más fácil de entender y leer teniendo en cuenta que cada condición puede ser un nombre de función largo o algo así.

Guy Coder
fuente
Lástima que nadie en esta página mencione la subcadena "rápido" o "rendimiento". Eso es lo que vine a aprender aquí.
Presidente de Dreamspace

Respuestas:

131

Prefiero la opción A

bool a, b, c;

if( a && b && c )
{
   //This is neat & readable
}

Si tiene variables / condiciones de método particularmente largas, puede simplemente saltar de línea

if( VeryLongConditionMethod(a) &&
    VeryLongConditionMethod(b) &&
    VeryLongConditionMethod(c))
{
   //This is still readable
}

Si son aún más complicados, entonces consideraría hacer los métodos de condición por separado fuera de la declaración if

bool aa = FirstVeryLongConditionMethod(a) && SecondVeryLongConditionMethod(a);
bool bb = FirstVeryLongConditionMethod(b) && SecondVeryLongConditionMethod(b);
bool cc = FirstVeryLongConditionMethod(c) && SecondVeryLongConditionMethod(c);

if( aa && bb && cc)
{
   //This is again neat & readable
   //although you probably need to sanity check your method names ;)
}

En mi humilde opinión, la única razón para la opción 'B' sería si tiene elsefunciones separadas para ejecutar para cada condición.

p.ej

if( a )
{
    if( b )
    {
    }
    else
    {
        //Do Something Else B
    }
}
else
{
   //Do Something Else A
}
Eoin Campbell
fuente
Me gusta. Aunque no soy un gran admirador de la idea del método, a menos que los métodos ya existan y devuelvan un valor booleano.
Thomas Owens
2
¿No estás evaluando todo sin una razón en el segundo ejemplo?
Odys
Usaría el '&&' antes de la condición. Es difícil tener condiciones con la misma longitud de caracteres que en el ejemplo.
Darkov
28

Otras respuestas explican por qué la primera opción suele ser la mejor. Pero si tiene varias condiciones, considere la posibilidad de crear una función (o propiedad) separada haciendo las verificaciones de condición en la opción 1. Esto hace que el código sea mucho más fácil de leer, al menos cuando usa buenos nombres de método.

if(MyChecksAreOk()) { Code to execute }

...

private bool MyChecksAreOk()
{ 
    return ConditionOne && ConditionTwo && ConditionThree;
}

Si las condiciones solo se basan en variables de alcance local, puede hacer que la nueva función sea estática y pasar todo lo que necesita. Si hay una mezcla, pase las cosas locales.

Torbjørn
fuente
2
Descubrí que esta es la condición más efectiva y más fácil de agregar más adelante
pbojinov
+1 al principio levanté una ceja, pero esta es realmente la mejor respuesta en mi humilde opinión. tener ese booleano isOkToDoWhatevercomo propiedad tiene mucho sentido.
Grinch
1
Pero esto simplemente mueve la misma condición compleja a otro lugar donde también debe ser legible, por lo que volvemos al punto de partida con esto. No se trata solo de la iflegibilidad de las declaraciones, sino de la legibilidad de las condiciones.
Robert Koritnik
@RobertKoritnik Entiendo lo que está diciendo, pero no creo que estemos de vuelta al punto de partida porque hemos reducido la complejidad que el lector debe considerar de una vez. Ella puede mirar las condiciones, O puede mirar el código usando las condiciones donde las condiciones tienen un nombre (con suerte) bonito. Al menos a menudo encuentro esto más fácil de asimilar, pero a veces es bueno tener todos los detalles en un solo lugar. Como siempre, depende.
Torbjørn
Es un gran punto utilizar buenos nombres de métodos y refactorizar la lógica.
JB Lovell
10

El primer ejemplo es más "fácil de leer".

En realidad, en mi opinión, solo deberías usar el segundo siempre que tengas que agregar alguna "lógica else", pero para un Condicional simple, usa el primer sabor. Si le preocupa la duración de la condición, siempre puede usar la siguiente sintaxis:

if(ConditionOneThatIsTooLongAndProbablyWillUseAlmostOneLine
                 && ConditionTwoThatIsLongAsWell
                 && ConditionThreeThatAlsoIsLong) { 
     //Code to execute 
}

¡Buena suerte!

David Santamaría
fuente
9

La pregunta fue formulada y, hasta ahora, ha sido respondida como si la decisión debiera tomarse por motivos puramente "sintácticos".

Yo diría que la respuesta correcta de cómo se establecen una serie de condiciones dentro de un si, debería depender también de la "semántica". Por lo tanto, las condiciones deben dividirse y agruparse de acuerdo con lo que van juntas "conceptualmente".

Si dos pruebas son realmente dos caras de la misma moneda, por ejemplo. si (x> 0) && (x <= 100) entonces póngalos juntos en la misma línea. Si otra condición es conceptualmente mucho más distante, por ejemplo. user.hasPermission (Admin ()) luego póngalo en su propia línea

P.ej.

if user.hasPermission(Admin()) {
   if (x >= 0) && (x < 100) {
      // do something
   }
}
interestar
fuente
7
if (   ( single conditional expression A )
    && ( single conditional expression B )
    && ( single conditional expression C )
   )
{
   opAllABC();
}
else
{
   opNoneABC();
}

Dar formato a varias expresiones condicionales en una declaración if-else de esta manera:

  1. permite una mejor legibilidad:
    a. todas las operaciones lógicas binarias {&&, ||} en la expresión que se muestra primero
    b. ambos operandos condicionales de cada operación binaria son obvios porque se alinean verticalmente
    c. Las operaciones de expresiones lógicas anidadas se hacen obvias usando sangría, al igual que las declaraciones anidadas dentro de la cláusula
  2. Requiere paréntesis explícitos (no depender de reglas de precedencia de operadores)
    a. esto evita errores comunes de análisis estático
  3. permite una depuración más sencilla
    a. deshabilite las pruebas condicionales individuales individuales con solo //
    b. establecer un punto de quiebre justo antes o después de cualquier
    ceg de prueba individual ...
// disable any single conditional test with just a pre-pended '//'
// set a break point before any individual test
// syntax '(1 &&' and '(0 ||' usually never creates any real code
if (   1
    && ( single conditional expression A )
    && ( single conditional expression B )
    && (   0
        || ( single conditional expression C )
        || ( single conditional expression D )
       )
   )
{
   ... ;
}

else
{
   ... ;
}
Sean
fuente
Este es mi método. El único problema que tengo es que todavía no he encontrado un embellecedor de código que ofrezca esto como una opción
Speed8ump
4

El segundo es un ejemplo clásico del antipatrón Arrow, así que lo evitaría ...

Si sus condiciones son demasiado largas, extráigalas en métodos / propiedades.

Omar Kooheji
fuente
3

El primero es más fácil, porque, si lo lees de izquierda a derecha, obtienes: "Si algo Y algo se Y algo ENTONCES", que es una oración fácil de entender. El segundo ejemplo dice "Si algo ENTONCES si algo ENTONCES si es algo más ENTONCES", que es torpe.

Además, considere si quisiera usar algunos OR en su cláusula, ¿cómo lo haría en el segundo estilo?

RB.
fuente
0

En Perl puedes hacer esto:

{
  ( VeryLongCondition_1 ) or last;
  ( VeryLongCondition_2 ) or last;
  ( VeryLongCondition_3 ) or last;
  ( VeryLongCondition_4 ) or last;
  ( VeryLongCondition_5 ) or last;
  ( VeryLongCondition_6 ) or last;

  # Guarded code goes here
}

Si alguna de las condiciones falla, simplemente continuará después del bloqueo. Si está definiendo cualquier variable que desee mantener después del bloque, deberá definirla antes del bloque.

Brad Gilbert
fuente
1
Eso se ve Perlish - en el "¿hace QUÉ?" sense;) Pero en realidad es legible, una vez que te acostumbras.
Piskvor salió del edificio el
-2

Me he enfrentado a este dilema durante mucho tiempo y todavía no puedo encontrar una solución adecuada. En mi opinión, la única buena manera es intentar primero deshacerse de las condiciones antes para no comparar repentinamente 5 de ellas.

Si no hay alternativa, como otros han sugerido, divídalo en nombres separados y acorte los nombres o agrúpelos y, por ejemplo, si todo debe ser verdadero, use algo como "si no hay falso en la matriz de x, entonces ejecute".

Si todo falla @Eoin Campbell dio muy buenas ideas.

Tiper Loc
fuente
Esto no agrega nada nuevo a las respuestas ya existentes.
jerney
-4

Cuando la condición es realmente compleja, uso el siguiente estilo (ejemplo de la vida real de PHP):

if( $format_bool &&
    (
        ( isset( $column_info['native_type'] )
            && stripos( $column_info['native_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['driver:decl_type'] )
            && stripos( $column_info['driver:decl_type'], 'bool' ) !== false
        )
        || ( isset( $column_info['pdo_type'] )
            && $column_info['pdo_type'] == PDO::PARAM_BOOL
        )
    )
)

Creo que es más agradable y legible que anidar varios niveles de if(). Y en algunos casos como este, simplemente no puede dividir una condición compleja en pedazos porque de lo contrario tendría que repetir las mismas declaraciones en if() {...}bloque muchas veces.

También creo que agregar algo de "aire" al código siempre es una buena idea. Mejora enormemente la legibilidad.

CodeDriller
fuente