web-dev-qa-db-fra.com

Remplacement des instructions if imbriquées

Ceci est lié à un chapitre de beautiful code . Et dans ce chapitre, je lis des informations sur les ifs imbriquées.

L’auteur parlait de ifs profondément imbriqués comme étant à l’origine des bogues et moins lisibles ..__ Et il parlait de remplacer les ifs imbriqués par des déclarations case et tables de décision

Quelqu'un peut-il illustrer comment supprimer les ifs imbriquées avec case (select case) et les tables de décision? 

27
Biswanath

Eh bien, pas directement une réponse à votre question puisque vous posez une question spécifique sur les déclarations de substitution/affaire, mais voici une question similaire.

Inverser l'instruction «if» pour réduire l'imbrication

Cela parle de remplacer les if imbriqués par des instructions de garde, qui retournent tôt, au lieu de vérifier progressivement de plus en plus de choses avant de choisir une valeur de retour.

Un exemple que j'essaie toujours de faire est de remplacer fortement les éléments imbriqués comme ceci (en fait, celui-ci n'est pas trop mal mais je les ai vus jusqu'à 8 ou 9 niveaux dans la nature):

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

avec ça:

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

J'essaie également de garder les actions aussi minimes que possible (les appels de fonction sont préférables pour cela) afin de maintenir la déclaration de commutateur compressée (vous n'avez donc pas besoin d'aller quatre pages à l'avance pour en voir la fin).

Je crois que les tables de décision ne font que placer des indicateurs indiquant quelles actions doivent être entreprises ultérieurement. La section "plus tard" est une séquence simple d'actions basée sur ces drapeaux. Je peux me tromper (ce ne sera pas la première ou la dernière fois :-).

Un exemple serait (la phase de mise en drapeau peut être compliquée si ses actions sont très 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.
10
paxdiablo

Qu'en est-il des ifs enchaînés?

Remplacer

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

    }
}

avec

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

Cela ressemble beaucoup à une instruction switch pour des conditions complexes.

9
Arkadiy

Transformez la condition en booléens, puis écrivez une expression booléenne pour chaque cas.

Si le code était:

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

    }
}

On peut l'écrire comme:

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

if (cond1) {do1;}
if (!cond1 and cond2) {do2;}
if (!cond1 and cond3) {do2;}
6
khivi

Pour les tables de décision, veuillez consulter ma réponse à à cette question , ou encore au chapitre 18 de Code Complete 2 .

3
Yuval F

Vous pouvez simplement interrompre une fois qu'une partie de la validation a échoué, par exemple.

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;
}
2
Alexis Paques

Les tables de décision sont où vous stockez la logique conditionnelle dans une structure de données plutôt que dans le code lui-même .

Donc au lieu de cela (en utilisant l'exemple de @ Pax):

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

vous faites quelque chose comme ça:

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 les possibilités pour i ne sont pas des nombres entiers bas, vous pouvez créer une table de recherche au lieu d'accéder directement à l'élément ith du tableau actions.

Cette technique devient beaucoup plus utile que les instructions ifs ou switch imbriquées lorsque vous devez prendre une décision sur plusieurs dizaines de valeurs possibles.

1
Paul Stephenson

Les instructions if et switch ne sont pas purement OO. Ce sont des logiques procédurales conditionnelles, mais faites du très bon travail! Si vous souhaitez supprimer ces instructions pour une approche plus OO, combinez les modèles "Etat" et "Descripteur" .

0
Anthony Mastrean

Vous pouvez également envisager d'utiliser le modèle Visiteur .

0
Drejc

Imbriqués si sont équivalents à l'opérateur logique ET

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

Code équivalent:

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

Dans les deux cas, lorsqu'une expression évalue false, l'expression suivante ne sera pas évaluée. Par exemple, si condition1 est fausse, la fonction () ne sera pas appelée et condition3 ne sera pas évaluée.

0
Demis Palma ツ