Ceci est lié à un chapitre de beautiful code . Et dans ce chapitre, je lis des informations sur les if
s imbriquées.
L’auteur parlait de if
s profondément imbriqués comme étant à l’origine des bogues et moins lisibles ..__ Et il parlait de remplacer les if
s imbriqués par des déclarations case
et tables de décision .
Quelqu'un peut-il illustrer comment supprimer les if
s imbriquées avec case
(select case
) et les tables de décision?
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.
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.
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;}
Pour les tables de décision, veuillez consulter ma réponse à à cette question , ou encore au chapitre 18 de Code Complete 2 .
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;
}
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 i
th du tableau actions
.
Cette technique devient beaucoup plus utile que les instructions if
s ou switch
imbriquées lorsque vous devez prendre une décision sur plusieurs dizaines de valeurs possibles.
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" .
Vous pouvez également envisager d'utiliser le modèle Visiteur .
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.