Considérez le code suivant:
public void doSomething(int input)
{
while(true)
{
TransformInSomeWay(input);
if(ProcessingComplete(input))
break;
DoSomethingElseTo(input);
}
}
Supposons que ce processus implique un nombre d'étapes fini mais dépendant de l'entrée; la boucle est conçue pour se terminer d'elle-même à la suite de l'algorithme et n'est pas conçue pour s'exécuter indéfiniment (jusqu'à ce qu'elle soit annulée par un événement extérieur). Parce que le test pour voir si la boucle doit se terminer se trouve au milieu d'un ensemble logique d'étapes, la boucle while elle-même ne vérifie actuellement rien de significatif; la vérification est effectuée à la place «appropriée» dans l'algorithme conceptuel.
On m'a dit que c'était du mauvais code, car il était plus sujet aux bogues car la condition de fin n'était pas vérifiée par la structure de la boucle. Il est plus difficile de comprendre comment vous sortiriez de la boucle, et pourrait inviter des bogues car la condition de rupture pourrait être contournée ou omise accidentellement en raison de changements futurs.
Maintenant, le code pourrait être structuré comme suit:
public void doSomething(int input)
{
TransformInSomeWay(input);
while(!ProcessingComplete(input))
{
DoSomethingElseTo(input);
TransformInSomeWay(input);
}
}
Cependant, cela duplique un appel à une méthode dans le code, violant DRY; s'ils TransformInSomeWay
étaient plus tard remplacés par une autre méthode, les deux appels devraient être trouvés et modifiés (et le fait qu'il y en ait deux soit moins évident dans un morceau de code plus complexe).
Vous pouvez également l'écrire comme:
public void doSomething(int input)
{
var complete = false;
while(!complete)
{
TransformInSomeWay(input);
complete = ProcessingComplete(input);
if(!complete)
{
DoSomethingElseTo(input);
}
}
}
... mais vous avez maintenant une variable dont le seul but est de déplacer la vérification de condition vers la structure de la boucle, et doit également être vérifiée plusieurs fois pour fournir le même comportement que la logique d'origine.
Pour ma part, je dis qu'étant donné l'algorithme que ce code implémente dans le monde réel, le code original est le plus lisible. Si vous le traversiez vous-même, c'est ainsi que vous le penseriez, et il serait donc intuitif pour les personnes familiarisées avec l'algorithme.
Alors, qui est "mieux"? vaut-il mieux confier la responsabilité de la vérification de l'état à la boucle while en structurant la logique autour de la boucle? Ou est-il préférable de structurer la logique d'une manière "naturelle" comme indiqué par les exigences ou une description conceptuelle de l'algorithme, même si cela peut signifier contourner les capacités intégrées de la boucle?
do ... until
construction est également utile pour ces types de boucles car elles n'ont pas besoin d'être "amorcées".