30 votes

Conditions «si» redondantes imbriquées

Existe-t-il un meilleur moyen (ou un nettoyage) d'écrire le code suivant?

 if(conditionX)
{
    if(condition1)
    {
        // code X1
    }
    else if(condition2)
    {
        // code X2
    }
}
else if(conditionY)
{
    if(condition1)
    {
        // code Y1
    }
    else if(condition2)
    {
        // code Y2
    }
}
 

J'ai quelques conditions supplémentaires, mais je suppose que vous comprenez.

33voto

dasblinkenlight Points 264350

Il existe quatre approches à ce problème, aucune n'est universelle:

  1. Tout laisser comme c'est , Il n'y a pas beaucoup de duplication de code ici. Si le calcul de condition1 et condition2 est délicat, les calculer à l'avance et de les stocker en bool variables
  2. Faire conditionX et conditionY d'obtenir un résultat qui vous permet d'unifier condition1 et condition2 - Ce n'est pas toujours possible, mais dans certaines situations, vous pourriez préparer une variable qui unifie les activités menées dans les deux branches, disons, à l'aide d'un pointeur de fonction ou un lambda.
  3. Mettre la logique de traitement dans les sous-classes avec des fonctions virtuelles pour éliminer la logique conditionnelle - Ceci n'est possible que lorsque votre conception initiale manqué une occasion à la sous-classe. Essentiellement, cette approche pousse la décision sur l' conditionX/conditionY en un lieu où une sous-classe est créée, puis "réutilise" cette décision plus tard en appelant un bon de remplacer une fonction virtuelle dans l'interface.
  4. Créer une combinaison numérique représentant les trois conditions, et de le convertir en switch - Cette astuce unifie les conditions, la réduction de la nidification.

Voici un exemple de la dernière approche:

int caseNumber = ((conditionX?1:0) << 3)
               | ((conditionY?1:0) << 2)
               | ((condition2?1:0) << 1)
               | ((condition1?1:0) << 0);
switch (caseNumber) {
    case 0x09:
    case 0x0D:
    case 0x0F: // code X1
        break;
    case 0x0A:
    case 0x0E: // code X2
        break;
    case 0x05:
    case 0x07: // code Y1
        break;
    case 0x06: // code Y2
        break;
}

25voto

paxdiablo Points 341644

Si votre problème concerne le code propre en termes de visualisation de la source, mon conseil serait de séparer les blocs dans leurs propres sections, quelque chose comme:

 if      (conditionX) processConditionX();
else if (conditionY) processConditionY();
 

etc.

Ensuite, dans les sous-fonctions, vous placez la "viande":

 void processConditionX (void) {
    if(condition1) {
        // code X1
    } else if(condition2) {
        // code X2
    }
}
 

Vous pouvez le modifier pour passer et renvoyer des paramètres si nécessaire et je rendrais les conditions et les noms de fonction un peu plus descriptifs, bien que je suppose que ce ne sont que des exemples ici.

14voto

barak manos Points 10969

Vous pouvez mettre en œuvre une machine d'état à la place:

#define COMBINATION(a,b,c,d) (((a)<<3)|((b)<<2)|((c)<<1)|((d)<<0))

switch (COMBINATION(conditionX,conditionY,condition1,condition2))
{
    case COMBINATION(0,0,0,0):           break;
    case COMBINATION(0,0,0,1):           break;
    case COMBINATION(0,0,1,0):           break;
    case COMBINATION(0,0,1,1):           break;
    case COMBINATION(0,1,0,0):           break;
    case COMBINATION(0,1,0,1): CodeY2(); break;
    case COMBINATION(0,1,1,0): CodeY1(); break;
    case COMBINATION(0,1,1,1): CodeY1(); break;
    case COMBINATION(1,0,0,0):           break;
    case COMBINATION(1,0,0,1): CodeX2(); break;
    case COMBINATION(1,0,1,0): CodeX1(); break;
    case COMBINATION(1,0,1,1): CodeX1(); break;
    case COMBINATION(1,1,0,0):           break;
    case COMBINATION(1,1,0,1): CodeX2(); break;
    case COMBINATION(1,1,1,0): CodeX1(); break;
    case COMBINATION(1,1,1,1): CodeX1(); break;
}

Cela comprend une seule branche de l'opération, de sorte qu'il est peut-être un peu plus efficace (même si elle inclut également un autre moteur d'exécution de calcul (à l' switch ligne)).

Pour être plus propre, je suppose que c'est une question de point de vue, mais le modèle ci-dessus vous donne également un bon moyen de détecter tous les non gérée branches au sein de votre code.

Veuillez noter que si toutes les variables de condition peut avoir une valeur autre que 1 ou 0, alors vous devriez:

#define COMBINATION(a,b,c,d) (((a)?8:0)|((b)?4:0)|((c)?2:0)|((d)?1:0))

Mise à jour (attribué à @Jonathan Wakely dans un des commentaires ci-dessous):

Si vous êtes à l'aide de C++11, alors vous pouvez remplacer l' COMBINATION macro avec un constexpr fonction de:

constexpr int COMBINATION(bool a,bool b,bool c,bool d)
{
    return ((int)a<<3) | ((int)b<<2) | ((int)c<<1) | ((int)d<<0);
}

6voto

CloudyMarble Points 16155

Je fournirais la décision à l'intérieur du premier if en tant que paramètre à des fonctions séparées qui décideraient alors du code à exécuter, comme:

 if(conditionX)
{
    Method1(Condition Parameters)
}
else if(conditionY)
{
    Method1(Condition Parameters)
}
 

Une autre façon serait de fournir toutes les informations nécessaires à une méthode de décision (matrice), cette méthode retourne un entier que vous utilisez dans une instruction switch pour décider du code à exécuter. De cette façon, vous séparez la logique de dessicion qui la rend lisible et facile à tester si nécessaire:

 DecisionMatrix(conditionX, conditionY, condition1, condition2)
{
  //  return a value according to the conditions for Example:
  // CoditionX + Condition1 => return 1
  // CoditionX + Condition2 => return 2
  // CoditionY + Condition1 => return 3
  // CoditionY + Condition2 => return 4
}

switch(DecisionMatrix)
{
    case 1: //run code X1       
    break;
    case 2: //run code X2
    break;
    case 3: //run code Y1       
    break;
    case 4: //run code Y2
    break;
}
 

4voto

Tanmay Patil Points 3909
  1. Le meilleur moyen serait d'utiliser le polymorphisme (Seulement si les blocs de code sont énormes)

  2. Si ils sont de petits fragments de code, la création de classes serait évidemment inutile.

    Donc, si il y a similitude dans tous les codes, je vous suggère d'apparence facile, mais la tâche vraiment difficile.

    • Essayez de paramétrer autant que vous le pouvez.
    • Créer une fonction qui prend ces et de les appeler dans les conditions
    • Maintenant, le code serait dans des blocs de fonction et plus "propre"

Il est toujours difficile de créer des choses simples.

if (conditionX) {
    method(parameterX);
else if (conditionY) {
    method(parameterY);
}

void method(ParameterType e) {
    if (condition 1) {
        // Code in terms of parameter e
    } else if (condition2) {
        // Code in terms of parameter e
    }
}

La condition que vous pouvez paramétrer doivent être gardés à l'extérieur.

Espérons que cette aide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X