123

私の同僚は、メソッド引数としてのブール値は受け入れられないと述べています。それらは列挙に置き換えられるものとします。最初は何のメリットもありませんでしたが、彼は私に例を教えてくれました。

何がわかりやすいですか?

file.writeData( data, true );

または

enum WriteMode {
  Append,
  Overwrite
};

file.writeData( data, Append );

今、私はそれを手に入れました!;-)
これは間違いなく、2番目のパラメーターとしての列挙によってコードがはるかに読みやすくなる例です。

それで、このトピックについてのあなたの意見は何ですか?

4

26 に答える 26

130

ブール値は「はい/いいえ」の選択肢を表します。「はい/いいえ」を表現したい場合は、ブール値を使用してください。一目瞭然です。

しかし、それが 2 つのオプションからの選択であり、どちらも明らかに yes または no ではない場合、enum の方が読みやすい場合があります。

于 2008-09-25T20:35:02.977 に答える
50

列挙型は、3 番目の選択肢 (またはそれ以上) が必要な場合に、将来の変更も可能にします。

于 2008-09-25T20:34:06.227 に答える
32

問題を最もモデル化するものを使用してください。あなたが与える例では、列挙型がより良い選択です。ただし、ブール値の方が優れている場合もあります。どちらがあなたにとってより理にかなっていますか:

lock.setIsLocked(True);

また

enum LockState { Locked, Unlocked };
lock.setLockState(Locked);

この場合、ブール値のオプションを選択する可能性があります。これは非常に明確で明確であり、ロックが 2 つ以上の状態になることはないと確信しているからです。それでも、2 番目の選択肢は有効ですが、不必要に複雑です。

于 2008-09-25T20:42:55.800 に答える
15

私にとって、ブール値も列挙型も使用するのは良いアプローチではありません。Robert C. Martin は、Clean Code Tip #12: Eliminate Boolean Argumentsでこれを非常に明確に捉えています。

ブール引数は、関数が複数のことを行うことを大声で宣言します。それらは紛らわしいので、排除する必要があります。

メソッドが複数のことを行う場合は、たとえばあなたの場合のように、2 つの異なるメソッドを記述する必要がfile.append(data)ありますfile.overwrite(data)

列挙を使用しても、物事が明確になるわけではありません。何も変更されません。これはまだフラグ引数です。

于 2009-11-03T23:59:31.787 に答える
13

あなたはほとんど自分でこれに答えたと思います。最終的な目的はコードをより読みやすくすることだと思います。この場合、列挙型はそれを行いました.IMOは、包括的なルールではなく最終目的を見るのが常に最善です.ガイドラインとして、つまり enum は一般的な bool や int などよりもコードで読みやすいことが多いですが、ルールには常に例外があります。

于 2008-09-25T20:35:37.657 に答える
13

キューバのミサイル危機の際、アドレー・スティーブンソンが国連のゾーリン大使に投げかけた質問を覚えていますか?

「あなたは今、世界の世論の法廷にいる 。イエスかノーかで答えることができる。あなたは[ミサイル]の存在を否定した。私はあなたのことを正しく理解しているかどうか知りたい....私は待つ用意がある」それがあなたの決断なら、地獄が凍りつくまで私の答えを聞いてください。」

メソッドにあるフラグがバイナリ決定に固定できるような性質のものであり、その決定が3 方向または n 方向の決定に決してならない場合は、ブール値を使用します。兆候: あなたのフラグはisXXXと呼ばれます。

モード スイッチの場合はブール値にしないでください。最初にメソッドを作成するときに考えたよりも、常にもう 1 つのモードがあります。

1 つ以上のモードのジレンマは、たとえば Unix に取り憑かれています。今日、ファイルまたはディレクトリが持つことができる許可モードは、ファイルの種類、所有権などに応じてモードの奇妙な二重の意味をもたらします。

于 2008-09-25T20:46:04.450 に答える
13

これが悪いことに遭遇した理由は2つあります。

  1. 一部の人々は次のようなメソッドを作成します。

    ProcessBatch(true, false, false, true, false, false, true);
    

    パラメータを混同するのは簡単すぎるため、これは明らかに悪いことであり、何を指定しているのか見ただけではわかりません。ただし、ブール値が 1 つだけでも悪くはありません。

  2. 単純な yes/no 分岐によってプログラム フローを制御することは、2 つのまったく異なる関数が厄介な方法で 1 つにまとめられていることを意味する可能性があるためです。例えば:

    public void Write(bool toOptical);
    

    本当に、これは2つの方法でなければなりません

    public void WriteOptical();
    public void WriteMagnetic();
    

    これらのコードはまったく異なる可能性があるためです。あらゆる種類の異なるエラー処理と検証を行う必要があるかもしれませんし、送信データを別の方法でフォーマットする必要さえあるかもしれません。Write()またはを使用するだけでは、それを伝えることはできませんWrite(Enum.Optical)(もちろん、必要に応じて、これらのメソッドのいずれかで内部メソッド WriteOptical/Mag を呼び出すこともできます)。

依存しているだけだと思います。#1を除いて、私はそれについてあまり大したことはしません。

于 2008-09-25T21:03:10.477 に答える
7

列挙型の方が優れていますが、ブール型のパラメーターを「受け入れられない」とは呼びません。小さなブール値を 1 つ入れて先に進む方が簡単な場合もあります (プライベート メソッドなどを考えてください)。

于 2008-09-25T20:35:39.297 に答える
6

ブール値は、Python や Objective-C などの名前付きパラメーターを持つ言語では問題ない場合があります。これは、名前がパラメーターの機能を説明できるためです。

file.writeData(data, overwrite=true)

また:

[file writeData:data overwrite:YES]
于 2008-09-25T20:50:02.833 に答える
4

あなたの同僚がよりよく守るかもしれないいくつかの規則は次のとおりです。

  • あなたのデザインを独断的にしないでください。
  • コードのユーザーに最も適したものを選択してください。
  • 今月の形が好きだからといって、星型のペグをすべての穴に打ち込もうとしないでください。
于 2010-03-26T18:22:46.233 に答える
4

多くの場合、列挙型の方がブール値よりも読みやすく、拡張しやすいのは事実ですが、「ブール値は受け入れられない」という絶対的なルールは馬鹿げています。柔軟性がなく、非生産的です。人間の判断の余地がありません。それらは有用であるため、ほとんどの言語で基本的な組み込み型です。他の組み込み型に適用することを検討してください。

このルールは単なるスタイルの問題であり、バグやランタイム パフォーマンスの可能性の問題ではありません。より良いルールは、「読みやすさのためにブール値よりも列挙型を優先する」ことです。

.Net フレームワークを見てください。ブール値は、かなりの数のメソッドでパラメーターとして使用されます。.Net API は完璧ではありませんが、パラメーターとしてブール値を使用することは大きな問題ではないと思います。ツールチップには常にパラメーターの名前が表示されます。また、この種のガイダンスを作成することもできます。メソッド パラメーターに関する XML コメントを入力すると、ツールチップに表示されます。

また、ブール値を列挙型に明確にリファクタリングする必要がある場合があることも付け加えておく必要があります。クラスまたはメソッド パラメータに 2 つ以上のブール値があり、すべての状態が有効であるとは限りません (たとえば、それらを持つことは有効ではありません)。どちらも true に設定されます)。

たとえば、クラスに次のようなプロパティがある場合

public bool IsFoo
public bool IsBar

そして、それらの両方を同時に true にするのはエラーです。実際に取得したのは 3 つの有効な状態であり、次のように表現する方が適切です。

enum FooBarType { IsFoo, IsBar, IsNeither };
于 2008-09-25T22:37:46.723 に答える
4

それが良いルールであることに私は同意しません。明らかに、Enum は場合によっては明示的または冗長なコードをより適切に作成しますが、原則として、到達しすぎているようです。

最初にあなたの例を挙げましょう: 良いコードを書くプログラマーの責任 (および能力) は、ブール型のパラメーターを持つことによって実際に危険にさらされることはありません。あなたの例では、プログラマーは次のように書くことで冗長なコードを書くことができました:

dim append as boolean = true
file.writeData( data, append );

または、より一般的な方法を好む

dim shouldAppend as boolean = true
file.writeData( data, shouldAppend );

2番目: CONSTを渡しているため、指定したEnumの例は「より良い」だけです。ほとんどのアプリケーションでは、関数に渡されるほとんどの場合ではないにしても、少なくともいくつかのパラメータは VARIABLES です。その場合、私の 2 番目の例 (変数に適切な名前を付ける) の方がはるかに優れており、Enum を使用してもメリットはほとんどありません。

于 2008-09-25T20:41:10.357 に答える
4

列挙型には明確な利点がありますが、すべてのブール値を列挙型に置き換えるだけではいけません。true/false が実際に何が起こっているかを表す最良の方法である場所がたくさんあります。

ただし、それらをメソッド引数として使用することは少し疑わしいです。なぜなら、真/偽が実際に何を意味するかを確認できるため、それらが何をすべきかを掘り下げないとわからないからです。

プロパティ (特に C#3 オブジェクト初期化子を使用) またはキーワード引数 (Ruby または Python 風) は、そうでなければブール値引数を使用する場所に移動するためのはるかに優れた方法です。

C# の例:

var worker = new BackgroundWorker { WorkerReportsProgress = true };

ルビーの例

validates_presence_of :name, :allow_nil => true

Python の例

connect_to_database( persistent=true )

私が考えることができる唯一のことは、ブール型のメソッド引数が正しいことであると考えることができるのは、プロパティもキーワード引数もない Java だけです。これが私が Java を嫌う理由の 1 つです :-(

于 2008-09-25T21:03:44.750 に答える
3

フレームワークの機能を拡張するつもりがない場合にのみ、ブール値を使用できます。列挙型を拡張でき、関数呼び出しの以前の実装を壊さないため、列挙型が優先されます。

Enum のもう 1 つの利点は、読みやすいことです。

于 2008-09-25T20:34:17.160 に答える
2

メソッドが次のような質問をする場合:

KeepWritingData (DataAvailable());

どこ

bool DataAvailable()
{
    return true; //data is ALWAYS available!
}

void KeepWritingData (bool keepGoing)
{
   if (keepGoing)
   {
       ...
   }
}

ブールメソッドの引数は、完全に理にかなっているようです。

于 2008-09-25T20:36:49.837 に答える
2

方法によります。メソッドが非常に明白に真/偽のことを行う場合、それは問題ありません。たとえば、以下のように [これがこのメソッドの最良の設計であると言っているわけではありませんが、使用法が明らかな例にすぎません]。

CommentService.SetApprovalStatus(commentId, false);

ただし、言及した例など、ほとんどの場合、列挙型を使用することをお勧めします。.NET Framework 自体には、この規則に従わない例が多数ありますが、それは、この設計ガイドラインがサイクルのかなり遅い時期に導入されたためです。

于 2008-09-25T20:37:54.377 に答える
2

それは物事をもう少し明確にしますが、インターフェイスの複雑さを大幅に拡張し始めます-追加/上書きなどの純粋なブール値の選択では、やり過ぎのように思えます. さらにオプションを追加する必要がある場合 (この場合は考えられません)、いつでもリファクタリングを実行できます (言語によって異なります)。

于 2008-09-25T20:39:53.513 に答える
2

列挙型は確かにコードを読みやすくします。注意すべきことがいくつかあります (少なくとも .net では)。

列挙型の基になるストレージは int であるため、デフォルト値は 0 になるため、0 が適切なデフォルトであることを確認する必要があります。(たとえば、構造体は作成時にすべてのフィールドがゼロに設定されているため、0 以外のデフォルトを指定する方法はありません。値が 0 でない場合は、int にキャストせずに列挙型をテストすることさえできません。スタイル悪い)

列挙型がコードに対して非公開である (公開されていない) 場合は、ここで読むのをやめることができます。

列挙型が何らかの方法で外部コードに公開されている場合、および/またはプログラムの外部に保存されている場合は、それらに明示的に番号を付けることを検討してください。コンパイラは自動的にそれらに 0 から番号を付けますが、値を指定せずに列挙型を再配置すると、欠陥が発生する可能性があります。

合法的に書ける

WriteMode illegalButWorks = (WriteMode)1000000;
file.Write( data, illegalButWorks );

これに対抗するには、特定できない列挙型 (パブリック API など) を使用するすべてのコードで、列挙型が有効かどうかを確認する必要があります。これは次の方法で行います

if (!Enum.IsDefined(typeof(WriteMode), userValue))
    throw new ArgumentException("userValue");

の唯一の注意点Enum.IsDefinedは、リフレクションを使用しており、速度が遅いことです。また、バージョン管理の問題もあります。列挙値を頻繁に確認する必要がある場合は、次の方法を使用することをお勧めします。

public static bool CheckWriteModeEnumValue(WriteMode writeMode)
{
  switch( writeMode )
  {
    case WriteMode.Append:
    case WriteMode.OverWrite:
      break;
    default:
      Debug.Assert(false, "The WriteMode '" + writeMode + "' is not valid.");
      return false;
  }
  return true;
}

バージョン管理の問題は、古いコードが 2 つの列挙型を処理する方法しか知らない可能性があることです。3 番目の値を追加すると、Enum.IsDefined は true になりますが、古いコードでは必ずしもそれを処理できるとは限りません。おっと。

列挙型でできることはさらに多く[Flags]、そのための検証コードは少し異なります。

ToString()また、移植性のために、列挙型にcallを使用Enum.Parse()し、それらを読み戻すときに使用する必要があることにも注意してください。両方ともToString()列挙型Enum.Parse()も処理できる[Flags]ため、それらを使用しない理由はありません。コードを壊さずに列挙型の名前を変更することさえできないため、これはさらに別の落とし穴です。

ですから、自分自身に尋ねるとき、上記のすべてを比較検討する必要がある場合があります

于 2008-09-25T21:27:44.567 に答える
1

私見では、2 つ以上のオプションが可能な状況では、列挙型が当然の選択であるように思われます。しかし、ブール値だけが必要な状況は間違いなくあります。その場合、boolが機能する列挙型を使用することは、4つが機能するときに7つの単語を使用する例になると言えます。

于 2008-09-25T20:38:03.610 に答える
0

ブール値は、2 つのこと (つまり、電球の状態、オンまたはオフ) のうちの 1 つにしかならない明らかなトグルがある場合に意味があります。それ以外では、何を渡そうとしているかが明確になるように記述するのが良いでしょう。たとえば、ディスクへの書き込み (アンバッファ、ラインバッファ、または同期) は、そのように渡す必要があります。今は同期書き込みを許可したくない場合でも (したがって、2 つのオプションに制限されています)、一目で何をするかを理解するために、より詳細にすることを検討する価値があります。

そうは言っても、False と True (ブール値の 0 と 1) を使用することもできます。後でさらに値が必要になった場合は、関数を拡張してユーザー定義の値 (2 と 3 など) と古い 0/1 の値をサポートします。うまく移植されるので、コードが壊れることはありません。

于 2008-09-25T20:38:40.410 に答える
0

オーバーロードを使用してさまざまな動作をモデル化する方が簡単な場合があります。あなたの例から続けるには:

file.appendData( data );  
file.overwriteData( data );

複数のパラメーターがあり、それぞれが固定されたオプションのセットを許可している場合、このアプローチは機能しなくなります。たとえば、ファイルを開くメソッドには、ファイル モード (開く/作成)、ファイル アクセス (読み取り/書き込み)、共有モード (なし/読み取り/書き込み) のいくつかの順列がある場合があります。構成の総数は、個々のオプションのデカルト積に等しくなります。当然、このような場合、複数のオーバーロードは適切ではありません。

列挙型を使用すると、場合によってはコードが読みやすくなりますが、一部の言語 (C# など) では正確な列挙値を検証するのが難しい場合があります。

多くの場合、ブール値のパラメーターが新しいオーバーロードとしてパラメーターのリストに追加されます。.NET での 1 つの例は次のとおりです。

Enum.Parse(str);  
Enum.Parse(str, true); // ignore case

後者のオーバーロードは、最初のバージョンより後のバージョンの .NET フレームワークで使用できるようになりました。

選択肢が 2 つしかないことがわかっている場合は、ブール値で問題ない可能性があります。古いライブラリは新しい列挙値をサポートしていない可能性があるため、バージョン管理を完全に無視することはできませんが、列挙型は古いコードを壊さない方法で拡張可能です。


編集

C# の新しいバージョンでは、名前付き引数を使用することができます。これにより、IMO では、列挙型と同じ方法で呼び出しコードをより明確にすることができます。上記と同じ例を使用します。

Enum.Parse(str, ignoreCase: true);
于 2008-10-11T09:11:44.657 に答える
0

2つのオプションがあるメソッドでは、列挙型が良い方法であることに同意します(そして、列挙型なしで可読性を持つことができるオプションは2つだけです)。

例えば

public void writeData(Stream data, boolean is_overwrite)

列挙型が大好きですが、ブール値も便利です。

于 2012-05-18T13:23:49.533 に答える
0

これは古い投稿の遅いエントリであり、ページのはるか下にあるため、誰も読むことはありませんが、まだ誰もそれを言っていないため....

インライン コメントは、予期しないbool問題を解決するのに大いに役立ちます。元の例は特に凶悪です: 関数宣言で変数に名前を付けようとすることを想像してみてください! それは次のようなものでしょう

void writeData( DataObject data, bool use_append_mode );

しかし、例として、それが宣言であるとしましょう。次に、他の方法では説明できないブール値の引数について、変数名をインライン コメントに入れました。比較

file.writeData( data, true );

file.writeData( data, true /* use_append_mode */);
于 2013-06-02T12:46:30.673 に答える
-1

それは本当に議論の正確な性質に依存します。yes/no または true/false でない場合は、列挙型を使用すると読みやすくなります。ただし、列挙型では、基になる型の未定義の値が渡される可能性があるため、引数を確認するか、許容可能なデフォルトの動作を行う必要があります。

于 2008-09-25T22:24:48.470 に答える
-1

例でブール値の代わりに列挙型を使用すると、メソッド呼び出しが読みやすくなります。ただし、これは私のお気に入りの C# のウィッシュ アイテム (メソッド呼び出しの名前付き引数) の代わりになります。この構文:

var v = CallMethod(pData = data, pFileMode = WriteMode, pIsDirty = true);

完全に読みやすくなり、IDE での表示方法に関係なく、メソッドの各パラメーターに最も適切な型を選択するという、プログラマーが行うべきことを行うことができます。

C# 3.0 では、コンストラクターで名前付き引数を使用できます。メソッドでもこれができない理由がわかりません。

于 2008-09-26T01:39:35.960 に答える
-1

ブール値true/falseのみ。したがって、それが何を表しているのかは明らかではありません。、などEnumの意味のある名前を付けることができます。したがって、列挙型の方が優れています。OVERWRITEAPPEND

于 2010-03-26T18:39:19.370 に答える