79

McConell のCode Completeを読んでいて、ブール変数を使用してコードを文書化する方法について説明しています。たとえば、次の代わりに:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
       ...
}

彼は次のように提案しています。

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

これは、論理的で、良い習慣であり、非常に自己文書化されているように思えます。ただし、この手法に出くわしたことがほとんどないため、この手法を定期的に使用することをためらっています。珍しいという理由だけで混乱するかもしれません。しかし、私の経験はまだそれほど多くはないので、このテクニックについてプログラマーの意見を聞くことに興味があります。また、誰かがこのテクニックを定期的に使用しているか、コードを読むときに頻繁に見たことがあるかどうか知りたいです。これは採用する価値のある規則/スタイル/テクニックですか? 他のプログラマーはそれを理解して評価するでしょうか、それとも奇妙だと思いますか?

4

14 に答える 14

55

ネストされすぎて複雑な式を、ローカル変数に割り当てられた単純なサブ式に分割してから、再度組み合わせるという手法は、非常に一般的で一般的な手法です。サブ式および/または式全体がブール値であるか、または他のタイプとほぼ同じです。適切に選択された名前を使用すると、この種の洗練された分解により可読性が向上し、優れたコンパイラは、元の複雑な式と同等のコードを問題なく生成できるはずです。

Haskell など、「代入」自体の概念を持たない一部の言語では、「部分式に名前を付ける」手法 ( whereHaskell の句)を使用できるようにする特殊な構造を導入しています。問題のテクニックの人気!-)

于 2010-03-19T14:49:28.300 に答える
16

私はそれを使用しましたが、通常はブール論理を再利用可能なメソッドにラップします (複数の場所から呼び出された場合)。

これは読みやすさに役立ち、ロジックが変更された場合でも、変更する必要があるのは 1 か所だけです。

他の人はそれを理解し、奇妙だとは思わないでしょう (千行関数しか書いたことがない人を除いて)。

于 2010-03-19T14:50:30.807 に答える
9

可能な限りそうするようにしています。確かに、コードの「余分な行」を使用していますが、同時に、2 つの値を比較する理由を説明しています。

あなたの例では、私はコードを見て、「大丈夫、なぜ人は値が0より小さいのを見ているのですか?」と自問します。2番目に、これが発生したときに一部のプロセスが終了したことを明確に伝えています。2番目のものであなたの意図が何であるかを推測する必要はありません.

私にとって大きな問題は、次のようなメソッドを見たときです。 DoSomeMethod(true); なぜ自動的に true に設定されるのですか? 次のようにはるかに読みやすいです

bool deleteOnCompletion = true;

DoSomeMethod(deleteOnCompletion);
于 2010-03-19T14:50:17.643 に答える
5

提供されたサンプル:

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

読みやすさを向上させ、ブール論理を保持するメソッドを使用するように書き直すこともできます(Konradが指摘したように)。

if (IsFinished(elementIndex) || IsRepeatedEntry(elementIndex, lastElementIndex)){
   ...
}

...

private bool IsFinished(int elementIndex) {
    return ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
}

private bool IsRepeatedEntry(int elementIndex, int lastElementIndex) {
    return (elementIndex == lastElementIndex);
}

もちろん、それは2つの追加の方法である代償を伴います。これを頻繁に行うと、コードが読みやすくなる可能性がありますが、クラスの透過性は低くなります。ただし、ここでも、追加のメソッドをヘルパークラスに移動することもできます。

于 2010-03-19T15:37:33.400 に答える
3

これが間違っていることがわかる唯一の方法は、ブールフラグメントに意味のある名前がなく、とにかく名前が選択された場合です。

//No clue what the parts might mean.
if(price>0 && (customer.IsAlive || IsDay(Thursday)))

=>

first_condition = price>0
second_condition =customer.IsAlive || IsDay(Thursday)

//I'm still not enlightened.
if(first_condition && second_condition)

これを指摘するのは、「すべてのコードにコメントする」、「3 つ以上の部分を持つすべての if-criteria に名前付きブール値を使用する」などのルールを作成して、次の並べ替えの意味的に空のコメントを取得するのが一般的であるためです。

i++; //increment i by adding 1 to i's previous value
于 2010-03-19T14:59:31.957 に答える
2

この方法では、必要以上に計算することに注意してください。コードから条件を取り出すため、常に両方を計算します (短絡はありません)。

となることによって:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
   ...
}

変換後:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) |
   (elementIndex == lastElementIndex)){
   ...
}

ほとんどの場合は問題ではありませんが、パフォーマンスの低下やその他の問題を意味する場合もあります。たとえば、2 番目の式で 1 ​​番目の式が失敗したと想定している場合などです。

于 2010-03-19T15:15:57.027 に答える
2

一時変数の代わりに関数/メソッドを作成する方が良いと思います。この方法では、メソッドが短くなるため、可読性も向上します。Martin Fowler の著書 Refactoring には、コードの品質を改善するための良いアドバイスがあります。特定の例に関連するリファクタリングは、「一時をクエリに置き換える」および「メソッドを抽出する」と呼ばれます。

于 2010-03-19T16:00:01.243 に答える
2

こうすることで

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

脳からロジックを取り除き、それをコードに入れます。これで、プログラムはあなたの意図を認識します。何かに名前
を付ける ときはいつでも、物理的な表現を与えます。それが存在します。 加工して再利用できます。

ブロック全体を述語として定義することもできます。

bool ElementBlahBlah? (elementIndex, lastElementIndex);

その関数で(後で)さらに多くのことを行います。

于 2010-03-19T15:09:03.027 に答える
2

bool式が複雑な場合は、 egを返す別の関数に移動するかisAnEveningInThePubAGoodIdea(dayOfWeek, sizeOfWorkLoad, amountOfSpareCash)、そのような複雑な式が不要になるようにコードを再検討します。

于 2010-03-19T15:11:10.180 に答える
2

個人的には、これは素晴らしい習慣だと思います。コードの実行への影響は最小限ですが、適切に使用すれば、後でコードを保守する際に非常に重要です。

于 2010-03-19T16:04:12.623 に答える
1

メソッドが成功の通知を必要とする場合: (c# の例)

bool success = false;

始めます。コードを次のように変更するまで、コードは失敗です。

success = true;

最後に:

return success;
于 2010-03-23T00:18:09.950 に答える
0

私の経験では、私はしばしばいくつかの古いスクリプトに戻って、「当時、私は一体何を考えていたのか」と疑問に思いました。例えば:

Math.p = function Math_p(a) {
    var r = 1, b = [], m = Math;
    a = m.js.copy(arguments);
    while (a.length) {
        b = b.concat(a.shift());
    }
    while (b.length) {
        r *= b.shift();
    }
    return r;
};

これは、次のように直感的ではありません。

/**
 * An extension to the Math object that accepts Arrays or Numbers
 * as an argument and returns the product of all numbers.
 * @param(Array) a A Number or an Array of numbers.
 * @return(Number) Returns the product of all numbers.
 */
Math.product = function Math_product(a) {
    var product = 1, numbers = [];
    a = argumentsToArray(arguments);
    while (a.length) {
        numbers = numbers.concat(a.shift());
    }
    while (numbers.length) {
        product *= numbers.shift();
    }
    return product;
};
于 2010-03-19T17:30:22.217 に答える
0

個別の変数を作成することはめったにありません。テストが複雑になったときに私がすることは、IF をネストしてコメントを追加することです。お気に入り

boolean processElement=false;
if (elementIndex < 0) // Do we have a valid element?
{
  processElement=true;
}
else if (elementIndex==lastElementIndex) // Is it the one we want?
{
  processElement=true;
}
if (processElement)
...

この手法の認められている欠点は、次に登場するプログラマーがロジックを変更する可能性がありますが、コメントを更新することを気にしないことです。これは一般的な問題だと思いますが、「顧客 ID を検証してください」というコメントが何度もあり、次の行で部品番号などを調べていて、顧客がどこにいるのか疑問に思っています。 IDが入ります。

于 2010-03-19T17:38:50.667 に答える
0

それはあなたやあなたのチームが好むスタイルによると思います。「変数を導入する」リファクタリングは便利かもしれませんが、そうでない場合もあります:)

そして、私は彼の以前の投稿でケビンに反対する必要があります. 彼の例は、導入された変数を変更できる場合に使用できると思いますが、メソッド宣言にパラメーター名があるため、1つの静的ブール値にのみ導入するのは役に立ちません。コードで複製するのはなぜですか?

例えば:

void DoSomeMethod(boolean needDelete) { ... }

// useful
boolean deleteOnCompletion = true;
if ( someCondition ) {
    deleteOnCompletion = false;
}
DoSomeMethod(deleteOnCompletion);

// useless
boolean shouldNotDelete = false;
DoSomeMethod(shouldNotDelete);
于 2010-03-19T14:54:02.873 に答える