Meilleur moyen de formater l'instruction if avec plusieurs conditions

88

Si vous souhaitez exécuter du code en fonction de deux conditions ou plus, quelle est la meilleure façon de formater cette instruction if?

premier exemple: -

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

Deuxième exemple: -

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

qui est plus facile à comprendre et à lire en gardant à l'esprit que chaque condition peut être un long nom de fonction ou quelque chose.

Guy Coder
la source
Dommage que personne sur cette page ne mentionne la sous-chaîne "rapide" ou "performance". C'est ce que je suis venu ici pour apprendre.
Dreamspace President

Réponses:

132

Je préfère l'option A

bool a, b, c;

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

Si vous avez des variables / conditions de méthode particulièrement longues, vous pouvez simplement les couper en ligne

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

S'ils sont encore plus compliqués, j'envisagerais de faire les méthodes de condition séparément en dehors de l'instruction 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 ;)
}

IMHO La seule raison de l'option «B» serait si vous avez des elsefonctions distinctes à exécuter pour chaque condition.

par exemple

if( a )
{
    if( b )
    {
    }
    else
    {
        //Do Something Else B
    }
}
else
{
   //Do Something Else A
}
Eoin Campbell
la source
Je l'aime. Bien que je ne sois pas un grand fan de l'idée de méthode, à moins que les méthodes n'existent déjà et retournent une valeur booléenne.
Thomas Owens
2
N'évaluez-vous pas tout sans raison dans le deuxième exemple?
Odys
J'utiliserais le '&&' avant la condition. Il est difficile d'avoir des conditions avec la même longueur de caractère que dans l'exemple.
Darkov
28

D'autres réponses expliquent pourquoi la première option est normalement la meilleure. Mais si vous avez plusieurs conditions, envisagez de créer une fonction (ou une propriété) distincte en effectuant les vérifications de condition dans l'option 1. Cela rend le code beaucoup plus facile à lire, du moins lorsque vous utilisez de bons noms de méthodes.

if(MyChecksAreOk()) { Code to execute }

...

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

Si les conditions ne reposent que sur des variables de portée locales, vous pouvez rendre la nouvelle fonction statique et transmettre tout ce dont vous avez besoin. S'il y a un mélange, passez dans le truc local.

Torbjørn
la source
2
J'ai trouvé que c'était la plus efficace et la plus facile à ajouter plus tard
pbojinov
+1 au début, j'ai haussé un sourcil mais c'est vraiment la meilleure réponse à mon humble avis. avoir ce booléen isOkToDoWhatevercomme propriété a beaucoup de sens.
grinch
1
Mais cela déplace simplement la même condition complexe ailleurs où elle doit également être lisible , nous revenons donc à la case départ avec cela. Il ne s'agit pas seulement de iflisibilité des instructions, mais plutôt de lisibilité des conditions.
Robert Koritnik
@RobertKoritnik Je comprends ce que vous dites, mais je ne pense pas que nous soyons revenus à la case départ car nous avons réduit la complexité que le lecteur doit prendre en compte en une seule fois. Elle peut regarder les conditions, OU elle peut regarder le code en utilisant les conditions où les conditions ont un joli nom (espérons-le). Au moins, je trouve souvent cela plus facile à grok, mais encore une fois, c'est bien d'avoir tous les détails en un seul endroit. Comme toujours, cela dépend.
Torbjørn
Excellent point en utilisant de bons noms de méthodes et la refactorisation de la logique.
JB Lovell
10

Le premier exemple est plus «facile à lire».

En fait, à mon avis, vous ne devriez utiliser le second que chaque fois que vous devez ajouter une "autre logique", mais pour un conditionnel simple, utilisez la première saveur. Si vous vous inquiétez de la durée de la condition, vous pouvez toujours utiliser la syntaxe suivante:

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

Bonne chance!

David Santamaria
la source
9

La question a été posée et a jusqu'ici reçu une réponse comme si la décision devait être prise uniquement pour des raisons «syntaxiques».

Je dirais que la bonne réponse sur la façon dont vous définissez un certain nombre de conditions dans un si, devrait également dépendre de la «sémantique». Les conditions doivent donc être décomposées et regroupées en fonction de ce que les choses vont ensemble «conceptuellement».

Si deux tests sont vraiment les deux faces d'une même médaille, par exemple. if (x> 0) && (x <= 100) alors mettez-les ensemble sur la même ligne. Si une autre condition est conceptuellement beaucoup plus éloignée, par exemple. user.hasPermission (Admin ()) puis placez-le sur sa propre ligne

Par exemple.

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

Formater plusieurs expressions conditionnelles dans une instruction if-else de cette façon:

  1. permet une meilleure lisibilité:
    a. toutes les opérations logiques binaires {&&, ||} dans l'expression montrée en premier
    b. les deux opérandes conditionnels de chaque opération binaire sont évidents car ils s'alignent verticalement
    c. Les opérations d'expressions logiques imbriquées sont rendues évidentes en utilisant l'indentation, tout comme l'imbrication des instructions à l'intérieur d'une clause
  2. nécessite des parenthèses explicites (ne repose pas sur les règles de priorité des opérateurs)
    a. cela évite une erreur d'analyse statique courante
  3. permet un débogage plus facile
    a. désactiver les tests conditionnels individuels avec juste un //
    b. définir un point de rupture juste avant ou après un test individuel
    ceg ...
// 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
la source
C'est ma méthode. Le seul problème que j'ai est que je n'ai pas encore trouvé un embellisseur de code qui offre cela en option
Speed8ump
4

Le second est un exemple classique de l' anti-motif de flèche, donc je l'éviterais ...

Si vos conditions sont trop longues, extrayez-les en méthodes / propriétés.

Omar Kooheji
la source
3

Le premier est plus facile, car si vous le lisez de gauche à droite, vous obtenez: "Si quelque chose ET quelque chose d'autre ET quelque chose d'autre ALORS", qui est une phrase facile à comprendre. Le deuxième exemple lit "Si quelque chose ALORS si quelque chose d'autre ALORS si quelque chose d'autre ALORS", ce qui est maladroit.

Demandez-vous également si vous vouliez utiliser des OR dans votre clause - comment feriez-vous cela dans le second style?

RB.
la source
1

Je crois que la switch...casedéclaration est la meilleure façon d'écrire du code ordonné dans cette circonstance, si le langage de programmation le prend en charge.

switch (//variable or Boolean) {
  case //Condition A:
  case //Condition B:
  case //Condition C:
    //Code to execute;
}
Kent
la source
Cela peut être bien, mais cela supprime «l'avantage» du «court-circuit» / de l'évaluation paresseuse.
TheLibrarian
Cette réponse est tout simplement fausse et en fait dangereuse. La question porte sur une condition conjonctive. Les instructions Switch ne sont une solution que pour les conditions disjonctives.
egyik le
0

En Perl, vous pouvez faire ceci:

{
  ( 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 l'une des conditions échoue, elle continuera simplement après le blocage. Si vous définissez des variables que vous souhaitez conserver après le bloc, vous devrez les définir avant le bloc.

Brad Gilbert
la source
1
Cela ressemble à Perlish - dans le "il fait quoi?" sense;) Mais c'est en fait lisible, une fois que vous vous y êtes habitué.
Piskvor a quitté le bâtiment
-2

Je suis confronté à ce dilemme depuis longtemps et je ne trouve toujours pas de solution appropriée. À mon avis, le seul bon moyen est d'essayer d'abord de se débarrasser des conditions avant de ne pas comparer soudainement 5 d'entre elles.

S'il n'y a pas d'alternative, comme d'autres l'ont suggéré - décomposez-la en deux et raccourcissez les noms ou regroupez-les et par exemple si tout doit être vrai, utilisez quelque chose comme "si aucun faux dans le tableau de x alors exécutez".

Si tout échoue, @Eoin Campbell a donné de très bonnes idées.

Tiper Loc
la source
Cela n'ajoute rien de nouveau aux réponses déjà existantes.
jerney
-4

Lorsque la condition est vraiment complexe, j'utilise le style suivant (exemple PHP réel):

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

Je pense que c'est plus agréable et lisible que d'imbriquer plusieurs niveaux de if(). Et dans certains cas comme celui-ci, vous ne pouvez tout simplement pas briser une condition complexe en morceaux, sinon vous devrez répéter les mêmes instructions en if() {...}bloc plusieurs fois.

Je crois aussi que l'ajout d'un peu «d'air» dans le code est toujours une bonne idée. Cela améliore considérablement la lisibilité.

CodeDriller
la source