ブールパラメータを使用して動作を決定するのは間違っていますか?


194

私は時々「違和感を感じる」練習を見てきましたが、それについて何が悪いのかを明確に説明することはできません。または多分それはちょうど私の偏見です。ここに行く:

開発者は、パラメータの1つとしてブール値を使用してメソッドを定義し、そのメソッドは別のメソッドを呼び出すなど、最終的にそのブール値は、特定のアクションを実行するかどうかを決定するためだけに使用されます。これは、たとえば、ユーザーが特定の権限を持っている場合、またはテストモード、バッチモード、またはライブモードの場合(またはそうでない場合)にのみアクションを許可するために、またはシステムが特定の状態。

さて、それを行う別の方法が常にあります。(パラメータを渡すのではなく)アクションを実行するときを照会するか、メソッドの複数のバージョン、またはクラスの複数の実装などを使用します。私の質問はこれをどのように改善するかではなく、むしろそれが本当に間違っているかどうか(私が疑うように)、もしそうなら、何が悪いのか。


1
これは、決定がどこに属するかという問題です。決定を散らかすのではなく、中央の場所で決定を移動します。これにより、ifがあるたびに2倍のコードパスを設定するよりも複雑さが低くなります。

28
マーティン・ファウラーは、これに関する記事を持っています:martinfowler.com/bliki/FlagArgument.html-
クリストファー・


@ChristofferHammarström素敵なリンク。私の説明と同じ考えを詳細に説明しているので、それを回答に含めます。
アレックス

1
ニックが言わなければならないことにいつも同意するわけではありませんが、この場合は100%に同意しますブール値パラメーターを使用しないでください
マルジャンヴェネマ

回答:


107

はい、これはおそらくコードの匂いであり、理解しにくく、簡単に再利用される可能性の低い保守不可能なコードにつながります。

他のポスターはコンテキストがすべてだと指摘しているように(1回限りの場合や、後でリファクタリングするために意図的に技術的負債が発生したとして慣行が認められている場合は、手に負えないでください)実行する特定の動作を選択する関数にするには、さらに段階的な改善が必要です。この関数をより小さな関数に分割すると、より凝集度の高い関数が生成されます。

それでは、高度に凝集した関数とは何ですか?

これは、1つのことと1つのことだけを行う機能です。

説明どおりに渡されるパラメーターの問題は、関数が2つ以上のことを実行していることです。ブール値パラメーターの状態に応じてユーザーのアクセス権をチェックする場合としない場合があり、その決定ツリーに応じて機能の一部を実行します。

アクセス制御の懸念をタスク、アクション、またはコマンドの懸念から分離する方がよいでしょう。

既に述べたように、これらの懸念は絡み合っていないようです。

したがって、凝集性の概念は、問題の関数が高度に凝集性ではなく、コードをリファクタリングして、より凝集性の高い関数のセットを生成できることを識別するのに役立ちます。

そのため、質問は修正できます。行動選択パラメーターを渡すことは、問題をどのように改善すればよいのでしょうか?

パラメータを完全に取り除きます。テスト中でもアクセス制御をオフにする機能を持つことは、潜在的なセキュリティリスクです。テスト目的で、アクセスチェックをまたは、許可されたアクセスシナリオとアクセスが拒否されたシナリオの両方をテストします。

参照:Cohesion(コンピューターサイエンス)


ロブ、Cohesionとは何か、またそれがどのように適用されるのかについて説明してください。
レイ

レイ、これについて考えれば考えるほど、アクセス制御を有効にするためのブール値がアプリケーションに導入するセキュリティホールに基づいたコードに反対する必要があると思います。コードベースの品質改善は素晴らしい副作用になります;)
ロブ

1
凝集力とその応用の非常に良い説明。これは本当により多くの票を得るはずです。また、セキュリティの問題にも同意します...それらがすべてプライベートな方法である場合、それはより小さな潜在的な脆弱性です
レイ

1
ありがとう、レイ。時間が許せば、簡単にリファクタリングできるように思えます。問題を強調するためにTODOコメントをドロップする価値があり、技術的な権限と、物事を成し遂げるために私たちが時々受けているプレッシャーに対する敏感さのバランスをとっています。
ロブ


149

非常に簡単な理由で、私はずっと前にこのパターンの使用をやめました。メンテナンス費用。何度かfrobnicate(something, forwards_flag)、コード内で何度も呼び出される関数があり、値falseがの値として渡されたコード内のすべての場所を見つける必要があることを発見しましたforwards_flag。それらを簡単に検索することはできないため、これはメンテナンスの頭痛の種になります。また、これらの各サイトでバグ修正を行う必要がある場合、見逃した場合は不幸な問題になる可能性があります。

しかし、この特定の問題は、根本的にアプローチを変更することなく簡単に修正できます。

enum FrobnicationDirection {
  FrobnicateForwards,
  FrobnicateBackwards;
};

void frobnicate(Object what, FrobnicationDirection direction);

このコードでは、のインスタンスを検索するだけで済みますFrobnicateBackwards。これを変数に割り当てるコードがいくつかあるため、いくつかの制御スレッドに従う必要がありますが、実際には、これはこの代替が正常に機能するほどまれであることがわかります。

ただし、少なくとも原則として、この方法でフラグを渡すことには別の問題があります。これは、この設計を持つ一部の(一部のみ)システムが、コードの深くネストされた部分(フラグを使用)の実装の詳細に関する知識を外部レイヤー(どの値を渡すかを知る必要がある)に公開しすぎる可能性があることですこのフラグで)。Larry Constantineの用語を使用するために、この設計では、セッターとブールフラグのユーザーとの間に強すぎる結合が存在する場合があります。フランキーですが、コードベースについて詳しく知らなくても、この質問についてある程度の確信を持って言うことは困難です。

あなたが与える特定の例に対処するために、私はそれぞれにある程度の懸念を持っていますが、主にリスク/正確さの理由があります。つまり、システムがどの状態にあるかを示すフラグをシステムで渡す必要がある場合、これを考慮すべきであるがパラメーターをチェックしないコードがあることに気付くかもしれません(渡されなかったため)この関数)。だから、パラメータを渡すために誰かが省略したため、バグがあります。

また、ほぼすべての関数に渡す必要があるシステム状態インジケーターは、実際には本質的にグローバル変数であることを認める価値があります。グローバル変数の欠点の多くが適用されます。多くの場合、そのデータに基づいて正しく動作する責任があるオブジェクト内にシステム状態(またはユーザーの資格情報、またはシステムのID)の知識をカプセル化することをお勧めします。次に、生データではなく、そのオブジェクトへの参照を渡します。ここの主要な概念はカプセル化です。


9
本当に素晴らしい具体的な例と、私たちが扱っているものの性質とそれが私たちにどのように影響するかについての洞察。
レイ

33
+1。できる限り列挙型を使用します。bool後で追加のパラメーターが追加され、呼び出しが次のようになり始める関数を見てきましたDoSomething( myObject, false, false, true, false )。追加のブール引数が何を意味するのかを理解することは不可能ですが、意味のある名前の列挙値では簡単です。
グレアムペロー

17
ああ、最後にフロブニケートする方法の良い例です。これを永遠に探しています。
アレックス・プリチャード

38

これは必ずしも間違っているわけではありませんが、コードの匂いを表しています

ブールパラメータに関して回避すべき基本的なシナリオは次のとおりです。

public void foo(boolean flag) {
    doThis();
    if (flag)
        doThat();
}

次に、電話をかけるとき、通常は電話をかけfoo(false)foo(true)必要な正確な動作に依存します。

これは、結束が悪い場合であるため、本当に問題です。メソッド間に依存関係を作成していますが、これは実際には必要ありません。

この場合に行うべきことは、別のパブリックメソッドとしてそのままにdoThisdoThatておきます。

doThis();
doThat();

または

doThis();

こうすることで、結合を作成せずに正しい決定を呼び出し元に任せます(ブール値のパラメーターを渡すように正確に)。

もちろん、すべてのブール値パラメーターがこのように悪い方法で使用されるわけではありませんが、間違いなくコードのにおいであり、ソースコードで多くを見れば疑わしくなります。

これは、私が書いた例に基づいてこの問題を解決する方法の一例です。別のアプローチが必要になる他のケースがあります。

同じ考えをさらに詳しく説明しているMartin Fowlerの良い記事があります。

PS:foo2つの単純なメソッドを呼び出す代わりにメソッドの実装がより複雑な場合は、小さなリファクタリング抽出メソッドを適用するだけで、結果のコードはfoo私が書いた実装に似たものになります。


1
「コードのにおい」という用語を呼び出してくれてありがとう。悪臭がすることは知っていましたが、その臭いが何であるかは十分に理解できませんでした。あなたの例は、私が見ているものとほぼ一致しています。
レイ

24
if (flag) doThat()内部foo()が正当である多くの状況があります。呼び出しに関する決定doThat()をすべての呼び出し元にプッシュすると、後でいくつかのメソッドを見つけた場合に削除する必要がある繰り返しを強制するため、flag動作もを呼び出す必要がありますdoTheOther()。後ですべての呼び出し元を精査するよりも、同じクラスのメソッド間に依存関係を置く方がはるかに好きです。
Blrfl

1
@Blrfl:はい、より簡単なリファクタリングは、doOneand doBothメソッド(それぞれfalseおよびtrueの場合)を作成するか、James Youngmanによって提案された個別の列挙型を使用すると
思います-hugomg

@missingno:あなたはまだ作るために発信者のうち、冗長なコードを押すと同じ問題があるだろうdoOne()か、doBoth()決断を。サブルーチン/関数/メソッドには引数があるため、動作を変えることができます。真のブール条件に列挙型を使用することは、引数の名前が既に何をするのかをすでに説明している場合、自分自身を繰り返すことによく似ています。
Blrfl

3
2つのメソッドを順番に呼び出すか、1つのメソッドのみを冗長とみなすことができる場合、try-catchブロックまたはif elseを記述する方法も冗長です。それらをすべて抽象化する関数を書くということですか?番号!注意してください。1つのメソッドを作成しても、他の2つのメソッドを呼び出すだけでは、必ずしも優れた抽象化を表すとは限りません。
アレックス

29

まず、プログラミングは科学であり、芸術です。したがって、プログラムの「間違った」方法と「正しい」方法はほとんどありません。ほとんどのコーディング標準は、一部のプログラマが有用と考える「好み」にすぎません。しかし、最終的にはかなりarbitrary意的です。そのため、パラメーターの選択肢自体に「間違った」ラベルを付けることは決してありません。また、ブールパラメーターほど一般的で有用なものではありません。多くの場合、状態をカプセル化するためのa boolean(またはそのための)の使用intは完全に正当化されます。

コーディングの決定は、概して、主にパフォーマンスと保守性に基づいている必要があります。パフォーマンスが危険にさらされていない場合(そして、あなたの例でこれがどのようになり得るか想像できません)、あなたの次の考慮事項は次のとおりです。直感的でわかりやすいですか?孤立していますか?連鎖関数呼び出しのあなたの例は、実際にはこの点で潜在的に脆いようです:あなたは変更することを決定した場合bIsUpにはbIsDown、コード内の他の場所があまりにも変更する必要がありますどのように多くの?また、パラメーターリストはバルーニングしていますか?関数に17個のパラメーターがある場合、読みやすさが問題になるため、オブジェクト指向アーキテクチャーの利点を理解しているかどうかを再検討する必要があります。


4
最初の段落の警告に感謝します。私は、「間違った」ということで、意図的に挑発的であること、そして確かに私たちは、「ベストプラクティス」と設計原理の分野で扱っていることを認め、物事のこれらの種類は、多くの場合、状況であることを、もう1つは複数の要因を検討する必要がありました
レイ

13
あなたの答えは、「関数に17個のパラメータがある場合、おそらく1つのパラメータが欠落している」というソースを思い出せないという引用を思い出させます。
ジョリスティマーマンズ

私はこれに非常に同意し、質問に適用して、はいはブールフラグを渡すことはしばしば悪い考えですが、悪い/良いほど単純ではないことを
言う...-JohnB

15

Robert C Martins Cleanのコード記事では、メソッドが複数のことを行うことを示すため、可能であればブール引数を削除する必要があると述べていると思います。メソッドは1つのことを実行する必要があり、私が思うのは彼のモットーの1つだけです。


@drezaあなたはカーリーズ法を参照しています。
-MattDavey

もちろん、経験があれば、そのような引数をいつ無視するかを知っておく必要があります。
gnasher729

8

ここで最も重要なことは実用的であることだと思います。

ブール値が動作全体を決定する場合、2番目のメソッドを作成します。

ブール値が真ん中の少しの動作を決定するだけの場合、コードの重複を減らすためにブール値を1つにしたい場合があります。可能であれば、メソッドを3つに分割することもできます。ブールオプションの2つの呼び出しメソッドと、大部分の作業を行うメソッドです。

例えば:

private void FooInternal(bool flag)
{
  //do work
}

public void Foo1()
{
  FooInternal(true);
}

public void Foo2()
{
  FooInternal(false);
}

もちろん、実際には、これらの両極端の間には常にポイントがあります。通常、私は自分が正しいと思うことだけを行ないますが、コードの重複が少ないという点で誤りを好むのです。


プライベートメソッドの動作を制御するためにブール型引数のみを使用します(以下を参照)。しかし、問題:一部のデュファがFooInternal将来の可視性を高めることに決めた場合、それは何ですか?
ADTC 14年

実際、私は別のルートに行きます。FooInternal内のコードは4つの部分に分割する必要があります。ブールのtrue / falseケースを処理する2つの関数、1つは前に発生する作業用、もう1つは後に発生する作業用です。次に、次のようにFoo1なります{ doWork(); HandleTrueCase(); doMoreWork() }。理想的には、doWorkおよびdoMoreWork関数はそれぞれ、分割のために2つの関数だけでなく、(1つ以上の)意味のある個別のアクションのチャンク(つまり、個別の関数)に分割されます。
jpaugh

7

不変のインスタンスを返すビルダーメソッドを使用して動作をカスタマイズするアプローチが好きです。GuavaでのSplitter使用方法は次のとおりです。

private static final Splitter MY_SPLITTER = Splitter.on(',')
       .trimResults()
       .omitEmptyStrings();

MY_SPLITTER.split("one,,,,  two,three");

これの利点は次のとおりです。

  • 優れた可読性
  • 設定方法とアクション方法の明確な分離
  • オブジェクトが何であるか、何をすべきか、何をすべきでないかを考えさせることにより、結束を促進します。この場合、それはSplitterです。someVaguelyStringRelatedOperation(List<Entity> myEntities)という名前のクラスを配置することはありませんが、クラスSplitterの静的メソッドとして配置することを考えますStringUtils
  • インスタンスは事前に構成されているため、依存関係を簡単に注入できます。クライアントは、正しい振る舞いを得るためにメソッドを渡すtruefalseメソッドを心配する必要はありません。

1
私はグアバの愛好家であり、伝道者としてあなたの解決策に賛成しています...しかし、私があなたが本当に探している部分をスキップするので、あなたに+1を与えることはできません、それは間違っている(または臭い)ものです他の方法について。私はそれがあなたの説明のいくつかで実際に暗黙的であると思うので、おそらくあなたがそれを明示できれば、それは質問によりよく答えるでしょう。
レイ

構成メソッドとアクトンメソッドを分離するというアイデアが気に入っています。
Sher10ck

グアバライブラリーへのリンクが壊れている
ジョシュ・ノエを

4

間違いなくコードの匂い単一責任原則に違反していない場合は、おそらく、「聞かないでください」に違反しています。考慮してください:

これらの2つの原則のいずれかに違反しないことが判明した場合でも、列挙型を使用する必要があります。ブールフラグは、マジックナンバーに相当するブールですfoo(false)と同じくらい理にかなっていbar(42)ます。列挙型は戦略パターンに役立ち、別の戦略を追加できる柔軟性があります。(それらに適切な名前付けることを忘れないでください。)

あなたの特定の例は特に気になります。このフラグが多くのメソッドを通過するのはなぜですか?これは、パラメーターをサブクラス分割する必要があるようです。


4

TL; DR:ブール引数を使用しないでください。

それらが悪い理由と、それらを交換する方法を以下に示します(太字)。


ブール引数は非常に読みにくいため、保守が困難です。主な問題は、引数に名前が付けられているメソッドシグネチャを読み取ると、目的が一般に明確になることです。ただし、ほとんどの言語では、通常、パラメーターに名前を付ける必要はありません。したがってRSACryptoServiceProvider#encrypt(Byte[], Boolean)、ブール型パラメーターが関数で使用される暗号化の種類を決定するようなアンチパターンがあります。

したがって、次のような呼び出しが行われます。

rsaProvider.encrypt(data, true);

読者は、単に地獄trueが実際に何を意味するかを判断するために、メソッドの署名を検索する必要があります。整数を渡すのはもちろん悪いことです。

rsaProvider.encrypt(data, 1);

同じくらい-またはむしろ:少しだけ教えてくれます。整数に使用する定数を定義した場合でも、関数のユーザーはそれらを単に無視してリテラル値を使用し続けることができます。

これを解決する最良の方法は、列挙を使用することです。RSAPadding2つの値を持つ列挙型を渡す必要がある場合:OAEPまたはPKCS1_V1_5、すぐにコードを読み取ることができます:

rsaProvider.encrypt(data, RSAPadding.OAEP);

ブール値には2つの値しか指定できません。つまり、3番目のオプションがある場合は、署名をリファクタリングする必要があります。一般に、後方互換性が問題になる場合、これは簡単に実行できないため、パブリッククラスを別のパブリックメソッドで拡張する必要があります。これはRSACryptoServiceProvider#encrypt(Byte[], RSAEncryptionPadding)、ブールの代わりに列挙(または、少なくとも列挙を模倣するクラス)を使用する場所を導入したときにMicrosoftが最終的に行ったことです。

パラメーター自体をパラメーター化する必要がある場合、パラメーターとして完全なオブジェクトまたはインターフェイスを使用する方が簡単な場合もあります。上記の例では、OAEPパディング自体をハッシュ値でパラメーター化して、内部で使用できます。現在、6つのSHA-2ハッシュアルゴリズムと4つのSHA-3ハッシュアルゴリズムがあるため、パラメーターではなく単一の列挙のみを使用すると、列挙値の数が爆発する可能性があることに注意してください)。


ブールパラメータは、メソッドまたはクラスが適切に設計されていないことを示す場合もあります。上記の例と同様に、.NET以外の暗号化ライブラリは、メソッドシグネチャでパディングフラグをまったく使用しません。


私が好きなほとんどすべてのソフトウェアの達人は、ブール引数に対して警告します。たとえば、Joshua Blochは高く評価されている「Effective Java」の本で彼らに警告しています。一般に、それらは単に使用されるべきではありません。理解しやすいパラメータが1つある場合に使用できると主張できます。しかし、その後も:Bit.set(boolean)おそらくより良い使用して実装された2つのメソッドをBit.set()Bit.unset()


コードを直接リファクタリングできない場合、少なくとも定数を読みやすくするために定数定義できます

const boolean ENCRYPT = true;
const boolean DECRYPT = false;

...

cipher.init(key, ENCRYPT);

以下よりもはるかに読みやすい

cipher.init(key, true);

次のような場合でも:

cipher.initForEncryption(key);
cipher.initForDecryption(key);

代わりに。


3

誰もnamed-parametersに言及していないことに驚いています

ブール値フラグで見られる問題は、それらが読みやすさを損なうことです。例えば、何んtrue

myObject.UpdateTimestamps(true);

行う?何も思いつきません。しかし、どうですか:

myObject.UpdateTimestamps(saveChanges: true);

これで、渡しているパラメーターの意味が明確になりました。変更を保存するように関数に指示しています。この場合、クラスが非パブリックであれば、ブール値パラメーターは問題ないと思います。


もちろん、クラスのユーザーに名前付きパラメーターの使用を強制することはできません。このため、enumデフォルトのケースの頻度に応じて、通常、1つまたは2つの別々の方法が適しています。これがまさに.Netの機能です。

//Enum used
double a = Math.Round(b, MidpointRounding.AwayFromZero);

//Two separate methods used
IEnumerable<Stuff> ascendingList = c.OrderBy(o => o.Key);
IEnumerable<Stuff> descendingList = c.OrderByDescending(o => o.Key); 

1
問題は、行動を決定するフラグよりも望ましいものではなく、そのようなフラグが臭いであるかどうか、そうである場合は、理由
レイ

2
@Ray:これら2つの質問に違いはありません。名前付きパラメーターの使用を強制できる言語、または名前付きパラメーターが常に使用されることが確実な場合(プライベートメソッドなど)、ブールパラメーターは適切です。名前付きパラメーターを言語(C#)で実施できず、クラスがパブリックAPIの一部である場合、または言語が名前付きパラメーターをサポートしていない場合(C ++)、コードmyFunction(true)が記述される可能性がある場合、コードは臭い。
BlueRaja-ダニーPflughoeft

名前付きパラメーターのアプローチはさらに間違っています。名前がないと、APIドキュメントを読むことを余儀なくされます。名前があれば、必要はないと思いますが、パラメータは間違った名前になる可能性があります。たとえば、(すべての)変更を保存するために使用できましたが、後で大きな変更(大きな値の場合)のみを保存するように実装が少し変更されました。
インゴ

@Ingo私は同意しません。これは一般的なプログラミングの問題です。別のSaveBig名前を簡単に定義できます。任意のコードを台無しにすることができますが、この種の台無しは名前付きパラメーターに固有のものではありません。
マールテンボデウェス

1
@Ingo:ばかに囲まれているなら、どこかに行って仕事を見つけます。そのようなことは、コードレビューの対象です。
gnasher729

1

私はそれについて何が悪いのかを明確に述べることはできません。

コードの匂いのように見え、コードの匂いのように感じ、そして-コードの匂いのような匂いがするなら、おそらくコードの匂いです。

あなたがしたいことは:

1)副作用のあるメソッドを避けます。

2)中央の正式なステートマシン(このような)で必要なステートを処理します。


1

私は、ブールパラメータを使用してパフォーマンスを決定しないためのすべての懸念に同意します。改善、可読性、信頼性、複雑さの低減、不十分なカプセル化と凝集によるリスクの低減、保守性による総所有コストの削減。

70年代半ばにハードウェアの設計を開始し、現在SCADA(監視制御およびデータ収集)と呼びます。これらは、マクロリモートコントロールを実行し、高速データを収集するEPROMのマシンコードを使用して微調整されたハードウェアです。

ロジックはMealeyMoore マシンと呼ばれ、現在は有限状態マシンと呼ばれています。これらは、実行時間が有限のリアルタイムマシンである場合を除き、上記と同じルールで実行する必要があり、目的を果たすためにショートカットを実行する必要があります。

データは同期ですが、コマンドは非同期であり、コマンドロジックはメモリレスブールロジックに従いますが、前、現在、および望ましい次の状態のメモリに基づいたシーケンシャルコマンドを使用します。それが最も効率的な機械語(64kBのみ)で機能するように、ヒューリスティックなIBM HIPO方式ですべてのプロセスを定義するように細心の注意が払われました。それは、ブール変数を渡し、インデックス付きブランチを実行することを意味する場合がありました。

しかし、今では大量のメモリとOOKの容易さにより、カプセル化は今日の不可欠な要素ですが、コードがリアルタイムおよびSCADAマシンコードでバイト単位でカウントされた場合のペナルティです。


0

必ずしも間違っているわけではありませんが、「ユーザー」の属性に応じたアクションの具体例では、フラグではなくユーザーへの参照を渡します。

これは、いくつかの点で明確になり、役立ちます。

呼び出しステートメントを読んだ人はだれでも、結果はユーザーによって変わることがわかります。

最終的に呼び出される関数では、ユーザー属性にアクセスできるため、より複雑なビジネスルールを簡単に実装できます。

「チェーン」内の1つの関数/メソッドがユーザー属性に応じて異なる処理を行う場合、「チェーン」内の他のメソッドの一部にユーザー属性に対する同様の依存関係が導入される可能性が非常に高くなります。


0

ほとんどの場合、この悪いコーディングを検討します。ただし、2つのケースが考えられますが、これは良いプラクティスかもしれません。なぜそれが悪いのかという多くの答えが既にあるので、私はそれが良いかもしれないときに2回提供します:

1つは、シーケンス内の各呼び出しがそれ自体で意味をなすかどうかです。呼び出し元のコード trueからfalseまたはfalseからtrueに変更される場合、または呼び出されるメソッドブールパラメーターを渡すのではなく直接使用するように変更される場合に意味があります。このような10回の呼び出しが連続して発生する可能性は小さいですが、発生する可能性があり、実行された場合は、プログラミングの実践として適切です。

2番目のケースは、ブール値を処理していることを考えると、少しのストレッチです。ただし、プログラムに複数のスレッドまたはイベントがある場合、パラメーターを渡すことが、スレッド/イベント固有のデータを追跡する最も簡単な方法です。たとえば、プログラムは2つ以上のソケットから入力を取得できます。あるソケットで実行されるコードは警告メッセージを生成する必要があり、別のソケットで実行されるコードは生成しない場合があります。次に、非常に高いレベルで設定されたブール値が、警告メッセージが生成される可能性のある場所への多くのメソッド呼び出しを介して渡されるようにします。複数のスレッドまたはインターリーブされたイベントにはそれぞれ独自の値が必要となるため、データはどのような種類のグローバルにも保存できません(非常に困難な場合を除きます)。

確かに、後者の場合には私はおそらくその唯一のコンテンツブールたクラス/構造体を作成して渡したいということを周りの代わりに。警告メッセージの送信など他のフィールドがすぐに必要になることはほぼ間違いないでしょう。


列挙型WARN、SILENTは、作成したクラス/構造(コンテキストなど)を使用する場合でも、より意味があります。または、実際にログを外部で設定するだけです-何も渡す必要はありません。
マールテンボデウェス

-1

コンテキストは重要です。このようなメソッドはiOSでかなり一般的です。よく使用される例の1つとして、UINavigationControllerはmethodを提供し-pushViewController:animated:animatedパラメーターはBOOLです。メソッドはどちらの方法でも基本的に同じ機能を実行しますが、YESを渡すと、あるView Controllerから別のView Controllerへの遷移をアニメーション化し、NOを渡すとアニメーション化しません。これは完全に合理的です。アニメーションを使用するかどうかを判断できるように、このメソッドの代わりに2つのメソッドを提供する必要があるのはばかげているでしょう。

Objective-Cでは、この種のことを正当化する方が簡単な場合があります。Objective-Cでは、メソッドの命名構文により、CやJavaなどの言語で得られるよりも各パラメーターのコンテキストが多くなります。それにもかかわらず、単一のパラメータをとるメソッドは簡単にブール値をとることができ、それでも意味があると思います。

file.saveWithEncryption(false);    // is there any doubt about the meaning of 'false' here?

21
実際にfalseは、このfile.saveWithEncryption例で何を意味するのか分かりません。暗号化せずに保存されるということですか?もしそうなら、なぜこのメソッドは名前に「暗号化あり」を含むのでしょうか?のようなメソッドがあることは理解できましたsave(boolean withEncryption)が、を見るfile.save(false)と、パラメーターが暗号化の有無にかかわらずパラメーターが示すことは一見して明らかではありません。実際、これはジェームズ・ヤングマンの最初のポイント、列挙型の使用についてだと思います。
レイ

6
別の仮説はfalse、同じ名前の既存のファイルを上書きしないことです。私が知っている不自然な例ですが、確実に関数のドキュメント(またはコード)を確認する必要があります。
ジェームズヤングマン

5
saveWithEncryption暗号化では保存されないことがあるという名前のメソッドはバグです。可能性がありますfile.encrypt().save()、またはJavaのようなnew EncryptingOutputStream(new FileOutputStream(...)).write(file)
クリストファーハン

2
実際には、それが言うこと以外の何かをするコードは動作せず、したがってバグです。saveWithEncryption(boolean)暗号化なしで保存できる名前のメソッドを作成するために飛ぶことはありませんsaveWithoutEncryption(boolean)
クリストファーハンマルストローム

2
明らかに「ここでの「偽」の意味についての疑念」があるため、この方法は悪いです。とにかく、私はそもそもそのようなメソッドを決して書かないでしょう。保存と暗号化は別々のアクションであり、メソッドは1つのことを実行して適切に実行する必要があります。方法のより良い例については、以前のコメントを参照してください。
クリストファーハン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.