制御構造ロジックの正しい順序 (true/false、false/true)?
-
04-07-2019 - |
質問
私はプログラミングの初心者なので、制御構造のロジックを順序付ける正しい方法があるかどうか疑問に思っています。
最も可能性の高いケースを最初にチェックするほうが自然なように思えますが、一部の制御構造は、偽のものをすべてチェックして真のものに到達しない限り機能しないような気がします (論理的推論?)。
この「否定的な」見方に適応するのは難しいでしょう。私は、すべてが真実であると仮定して、より前向きな見方を好みます:)
解決
ほとんどの場合、実行速度よりも読みやすさが重要です。したがって、私はしようとします 次のアプローチを使用して、理解しやすいように最適化する:
すべての「アサーション」チェックは事前に行われます。これにより、すべての誤ったケースが最初から処理されることが保証されます。これは、null-pointer-checksで特に重要です。例:
if(arg == null){ throw new IllegalArgumentException(); // harsh (correct) } // or if(arg == null){ arg = ""; // forgiving (lazy) }
次に、各ifステートメントでのみ1つの条件をチェックしようとします。の代わりに
if(condition1 && condition2) { ... } else { ... }
iは一般的に好む
if(condition1) { if(condition2) { ... } else { ... } } else { ... }
このアプローチは、ブレークポイントを設定するのが簡単であり、ロジックをより曖昧にします。
否定を避けます。の代わりに
if(! condition) { ...a... } else { ...b... }
ものはより良く再配置されます
if(condition) { ...b... } else { ...a... }
最後に、ブール値の結果を返すすべてのメソッドには、「ポジティブ」が必要です。結果の意味を示す名前:
boolean checkSomething(Something x){ ... } // bad -- whats the result? boolean isSomethingInvalid(Something x){ ... } // better, but ... boolean isSomethingValid(Something x){ ... } // best, no "mental negation"
他のヒント
このトピックについては、McConnell's に優れた議論があります。 コードの完成. 。ぜひお勧めしたい本です。いずれにせよ、関連する議論は初版の 706 ~ 708 ページ、または 10 ページにあります。第 2 版の 749 ~ 750 (台座に感謝)。その本から:
最初に実行される可能性が最も高く、最も可能性の高いテストが実行されるように、テストを配置します。通常のケースを簡単にドロップすることができ、非効率性がある場合は、例外を処理する必要があります。
条件ステートメントの値に加えて考慮すべきことがあります。たとえば、コードのブロックのサイズが大幅に異なる場合、見やすいように小さなブロックを最初に配置することができます。 (大きなブロックが本当に大きい場合は、リファクタリングするか、おそらく別のメソッドに引き出す必要があります。)
if( condition is true ) {
do something small;
} else {
do something;
and something else;
. . .
and the 20th something;
}
条件内では、はい、一部の言語が式の一部が偽になると式の評価を停止する言語があります。コードにある種のis-definedロジックを含める場合、これは覚えておくことが重要です。言語が式全体を評価する場合、これを行う必要があります。
if( variable is defined ) {
if( variable == value ) {
...
}
}
これよりも:
if( (variable is defined) && (variable == value) ) {
...
}
「正しい」とは思わない条件を設計する方法。コーディング標準を持つ会社で働いている場合は、それが標準に含まれているかどうかを確認する必要があります。 (私が働いた最後の場所では、合理的な数の標準が定義されていましたが、条件付きロジックの書き方を指定していませんでした。)
一般的には、最初に予期しない項目をチェックするため、プログラムの例外的な流れに対処する必要があります。
そのようにして、「セットアップ」を開始する前に例外/中止操作をスローできます。通常のプログラムフローの場合。
この質問も参照してください:
私は、読者が取り入れなければならない情報量を最小限に抑えるように自分の条件を構築することを目指しています。ポジティブを証明するために、ネガティブをテストする方が簡単な場合があります。
例-2つの日付の期間が別の2つの日付の期間と交差するかどうかを確認するテストは、2つの期間が交差しないテストとして記述しやすい
単純なyesまたはエラーの質問の場合、通常、エラー処理ブランチがelse節になるように構成します。 yesまたはnoの質問(つまり、どちらの分岐もエラーではない)の場合、それは純粋に自然なことを判断するための判断です。コードの中心が実行される前に多くのテストを行う必要がある場合、私は通常、ネガティブなテストが最初に来て、何らかの形で後続のコードをスキップするように構造化しようとします(関数から戻る、ブレークする、または続行するループ)。
いずれか/または。私は通常、「ネガティブ」アプローチを使用します。
if(!何か) {
}
これは質問の範囲から少し外れていますが、通常はメソッドを高速で失敗させたいと考えています。このため、コードの後半まで引数を使用しない場合でも、メソッドの先頭ですべての引数検証を行う傾向があります。これは読みやすさを損ないますが、メソッドが本当に長い場合のみです(画面からスクロールして表示する必要があります)。もちろん、それはそれ自体がコードの匂いであり、リファクタリングされる傾向があります。
一方、チェックが単純ではなく、とにかくチェックするだけの別のメソッドに渡す場合、現在のメソッドをチェックインするコードを繰り返しません。ほとんどのものと同様に、バランスがあります。
(コンテキスト:Java)
READABILITY1:より小さいコードブロックに解決される条件が最初になります
if (condition) {
smallBlock();
} else {
bigBlockStart();
........
bigBlockEnd();
}
READABILITY2:否定記号に気付かない方が簡単なので、肯定的なアサーションが最初になります
MAKEING SENSE:Assert.blabla()を使用してメソッドのすべての前提条件をアサートし、メソッドの機能のみに条件を使用します。