次のコードを検討してください。
public void doSomething(int input)
{
while(true)
{
TransformInSomeWay(input);
if(ProcessingComplete(input))
break;
DoSomethingElseTo(input);
}
}
このプロセスには、有限であるが入力依存のステップ数が含まれると仮定します。ループは、アルゴリズムの結果としてそれ自体で終了するように設計されており、無期限に実行するように設計されていません(外部イベントによってキャンセルされるまで)。ループを終了するかどうかを確認するテストは、論理的な一連のステップの途中で行われるため、現在、whileループ自体は意味のあるものをチェックしません。代わりに、チェックは概念アルゴリズム内の「適切な」場所で実行されます。
終了条件がループ構造によってチェックされないため、バグが発生しやすいため、これは悪いコードだと言われました。ループを終了する方法を理解することはより困難であり、将来の変更を考慮して誤ってブレーク条件がバイパスまたは省略される可能性があるため、バグを招く可能性があります。
これで、コードは次のように構成できます。
public void doSomething(int input)
{
TransformInSomeWay(input);
while(!ProcessingComplete(input))
{
DoSomethingElseTo(input);
TransformInSomeWay(input);
}
}
ただし、これはコード内のメソッドの呼び出しを複製し、DRYに違反します。TransformInSomeWay
後で他のメソッドに置き換えられた場合、両方の呼び出しを見つけて変更する必要があります(2つの呼び出しがあるという事実は、より複雑なコードではあまり明らかではありません)。
次のように書くこともできます。
public void doSomething(int input)
{
var complete = false;
while(!complete)
{
TransformInSomeWay(input);
complete = ProcessingComplete(input);
if(!complete)
{
DoSomethingElseTo(input);
}
}
}
...しかし、条件チェックをループ構造にシフトすることだけが目的の変数があり、元のロジックと同じ動作を提供するために複数回チェックする必要があります。
私の側では、このコードが実際に実装しているアルゴリズムを考えると、元のコードが最も読みやすいと言います。あなたがそれを自分で行っていた場合、これはあなたがそれについて考える方法ですので、アルゴリズムに精通している人々にとって直感的です。
では、どちらが「良い」のでしょうか?ループの周りのロジックを構築することにより、whileループに条件チェックの責任を与える方が良いでしょうか?または、ループの組み込み機能をバイパスすることを意味する場合でも、要件またはアルゴリズムの概念的な説明で示されているように、「自然な」方法でロジックを構築する方がよいでしょうか?
do ... until
構造は、「プライミング」する必要がないため、これらの種類のループにも役立ちます。