オプションのパラメーターは役に立ちますか、それともアプリケーションのメンテナンスの妨げになりますか?[閉まっている]


14

タイトルに記載されているように、C#で使用されるパラメータなどのオプションのパラメータは有用ですか、それともアプリケーションのメンテナンスの妨げになり、コードを理解しにくくするために避けるべきですか?


3
免責事項:間違った手の言語機能はすべて悪用される可能性があります。言語がスマートな方法でこれを実装し、この言語機能が退屈な方法で既存の言語機能とあまり重ならない場合、それらは問題なく、実際非常に便利です。Pythonには、きちんとしたパラメーターのパッキング/アンパッキングと、その他のパラメーター「トリック」(Perlではなく、良い意味でのトリック)があります。
ジョブ

オプションのパラメーターを使用せずにExcelに接続するC#でアプリを作成してみてください。それは合理的な疑いを超えてあなたの質問に答えるべきです。
ダンク

回答:


22

私の経験では、オプションのパラメーターは良いことでした。常にデフォルト値を取得して、何が呼び出されているかを知ることができるので、それらを混乱させることはありません(少なくとも実際の関数ほど混乱することはありません)。

それらの用途の1つは、すでに一般的に使用されている関数、または少なくともパブリックインターフェイスで別のパラメーターを追加する必要がある場合です。それらがなければ、別の引数を持っている関数を呼び出すために元の関数をやり直す必要があり、引数を複数回追加すると、それは本当に古くなる可能性があります。


1
+1そして、それは、必要なnew Circle(size, color, filled, ellipseProportions)場所sizecolor必須などの引数を追加するオーバーロードされたメソッドで価値があり、残りはデフォルトです。
マイケルK

15

一般に、多くの/オプションのパラメーターが頻繁に必要な場合、関数の実行が多すぎるため、分割する必要があります。SRP(単一責任原則)に違反している可能性があります。

グループ化できるパラメーターを探します。たとえば(xとy、ポイントになります)。

これらのオプションのパラメータはデフォルトのフラグですか?フラグを使用している場合、関数を分割する必要があります。

これは、オプションのパラメーターを使用すべきではないということではありませんが、一般的に、1つまたは2つ以上のパラメーターがコードのにおいを示唆しています。

また、関数が実際にはクラスであり、オプションのパラメーターがプロパティに変更され、必要なパラメーターがコンストラクターの一部である必要があるという手掛かりになる場合もあります。


1
慎重に+1してください。どんなに優れた機能でも、悪用される可能性があります。
マイケルK

3
これは、APIのユーザーが少なくとも6つのクラスと15の関数を使用して最も単純なことを実現する必要がある、過剰設計されたラビオリコードを生成するための素晴らしいアドバイスです。
dsimcha

1
@dsimcha、どうやって私が書いたものからそれを得るのですか?ワオ。説明してください?これは、多くのオプションパラメータがある場合に得られる「スーパー機能」を持つのと同様に悪い設計になります。SOLIDの設計原則と、テスト可能なコードの記述について読んでください。TDDを使用することが望ましい。次に戻って、関数のパラメーターを減らすことは悪いことだと説明してください。
CaffGeek

1
テスト可能なコードは優れていますが、きれいで使いやすいAPIであり、あまりきめ細かすぎたり冗長になったりせず、関数が適切な抽象化である場合にクラスをくつがえしません。高レベルの抽象化で定義された責任を持つ単一責任原則を信じています。責任が低すぎるレベルで定義されている場合、個々のユニットが過度に単純化され、相互作用が過度に複雑になります。
dsimcha

1
@dsimcha、あなたはポイントを逃しています。個々のユニットは個々のユニットのままにして、単一の機能にまとめてはなりません。また、それらがすべて公的にアクセス可能な機能であることも意味しません。APIはコードへのゲートウェイであり、簡潔で簡潔でなければなりません。いくつかのオプションパラメータを持つ関数は、クリーンでも簡潔でもありません。ただし、単一の関数を論理パラメーターでオーバーロードする方がはるかに明確です。たとえば、多くのAPIには2つのパラメーターがオプションですが、どちらか一方が必要な関数があります。両方がオプションとしてマークされている場合、それについて明確なことは何ですか?
CaffGeek

4

オプションのパラメーターは問題ありません

通常、正当な理由は、a)メソッドの引数がたくさんある可能性があるが、APIが乱雑になるのを恐れてオーバーロードしたくないということ、またはb)可能な引数がすべてわからないときにユーザーに強制的に配列を提供させたくない。いずれの場合も、オプションのパラメーターがきちんとエレガントな方法で助けになります。

ここではいくつかの例を示します。

1.オーバーロードを避けたい、配列を指定したくない

C、Perl、Javaなどのprintf()を見てください。これは、オプションのパラメーターの威力を示すすばらしい例です。

例えば:

printf("I want %d %s %s",1,"chocolate","biccies");

printf("I want %d banana",1);

オーバーロード、配列、シンプルで直感的ではありません(標準の文字列形式コードを理解したら)。一部のIDEでは、フォーマット文字列がオプションのパラメーターと一致しない場合でも通知します。

2.デフォルトの使用を許可し、メソッドのユーザーから非表示にしたい

sendEmail( "test@example.org");

sendEmailメソッドは、さまざまな必須値が欠落していることを検出し、定義済みのデフォルト(subject、body、cc、bccなど)を使用してそれらを埋めます。APIはクリーンでありながら柔軟です。

パラメーターが多すぎることに注意

ただし、他の人が述べているように、メソッドに必須のパラメーターが多すぎるということは、おそらく設計に何か問題があることを示しています。開発者が偶然に切り替えて実行時に奇妙な結果をもたらす可能性があるため、同じタイプを共有している場合、これは特に当てはまります。

String myMethod(String x, String y, String z, String a, int b, String c, int d) {}

Introduce Parameter Objectリファクタリングを作成する理想的な候補です

String myMethod(ParameterObject po) {}

class ParameterObject {
  // Left as public for clarity
  public String x;
  public String y;
  ... etc

}

これにより、指定された仕様をパラメーターオブジェクトとして持つFactoryパターンに基づいて、より優れたデザインを作成できます。


1
printfのような文字列フォーマット関数はルールの例外です。オプションパラメーターの無制限のリストを使用している間は、実装方法にかかわらず、引数はオプションパラメーターというよりも配列のようです。
CaffGeek

@Chadオプションのパラメーターと、コードの匂いに移行するタイミングを区別するために、回答を調整しました(回答で述べたように)。
ゲイリーロウ

@Gary Rowe、オプションのパラメーターが多すぎると、ほとんどの場合に問題が生じます。
-CaffGeek

@Chad私は同意しますが、ほとんどの言語は、オプション引数の数に制限を指定する方法を提供しないため、すべてまたはゼロのアプローチです。メソッドを強制するためにメソッドに任せる必要があり、明らかにメソッドが500個の変数を処理している場合は、リファクタリングする必要があります。
ゲイリーロウ

@Gary Rowe、「ほとんどの言語はオプションの引数の数に制限を指定する方法を提供していません」とはどういう意味ですか?ほとんどの言語では、そのようにマークするか、関数を呼び出すときに値を提供しませんが、関数ヘッダーにはパラメーターが定義されています。確かに、一部の言語では、定義済みのパラメーターを入力した後、必要な数のパラメーターを追加できますが、ここで説明しているオプションのパラメーターの種類とは思いません。(文字列形式の例外を除く)
CaffGeek

2

C#のデフォルトパラメータの問題の1つ(void DoSomething(int x = 1)を考えています)は、定数であるということです。つまり、デフォルトを変更すると、そのメソッド呼び出しのコンシューマーを再コンパイルする必要があります。これは簡単ですが、危険な場合があります。


1

それはあなたのコードが何をしているかに依存します。賢明なデフォルトがある場合はオプションのパラメーターを使用する必要がありますが、賢明なデフォルトがない場合はオプションのパラメーターを追加するとコードがより複雑になります。多くの場合、オプションのパラメーターは、nilチェックを回避し、分岐ロジックを切り取るための適切な方法です。Javascriptにはオプションのパラメーターはありませんが、||でそれらをエミュレートする方法があります (論理的または)データベース関連のものを実行するときに常に使用します。ユーザーが値を提供しない場合、||の助けを借りて自分の値を置き換えるからです。これにより、大量のif thenステートメントを記述する手間が省けます。


1

オプションのパラメーターは、単純なものを単純なものと複雑なものを同時に可能にする優れた方法です。少なくとも迅速で汚いユースケースで、ほとんどのユーザーが望む明確で合理的なデフォルトがある場合、関数を呼び出すたびに手動で指定するために定型句を記述する必要はありません。一方、人々がそれを変更したいと思う正当な理由があるかもしれないならば、それは暴露される必要があります。

クラスを使用することは、クラスが行うことの典型的なメンタルモデルと冗長で非効率的で一貫性がないため、ひどい解決策です。関数は、動詞の完璧な抽象化です。つまり、何かをして戻ります。クラスは名詞の正しい抽象化です。つまり、状態を持ち、いくつかの方法で操作できるものです。前者をAPIユーザーのメンタルモデルにする必要がある場合は、クラスにしないでください。


1

オプションの引数の問題は、関連するコードを新しい関数に抽出するのではなく、関数に対する引数がますます増えているということです。これはphpで極端に行われます。例えば:

bool array_multisort ( array &$arr [, mixed $arg = SORT_ASC
                      [, mixed $arg = SORT_REGULAR [, mixed $... ]]] )

1

オプションのパラメーターは、基本的に関数をオーバーロードする別の方法です。したがって、これは基本的に次のようになります:「関数のオーバーロードが悪い」?


1

私は当初、Pythonでこの機能を気に入っており、既に使用されているメソッドを「拡張」するためにそれを使用しました。それは見た目も簡単でしたが、すぐに戻ってきました。オプションのパラメーターを追加すると、古いクライアントが依存していた既存のメソッドの動作が、既存のユニットテストケースでキャッチされない方法で変更されたためです。基本的にこれを行うことは、Open Closed Principleを破ることです。コードは拡張のために開かれていますが、変更のために閉じられています。したがって、この機能を使用して既存のコードを変更することはお勧めできません。しかし、最初から使用する場合は大丈夫


0

オプションのパラメーターを使用するよりも、異なるシグネチャ(つまりパラメーター)で関数をオーバーロードする方が良いと思います。


どうして?すべてのメソッドは、同じ基本的な機能を持っている場合は、デフォルトのparamsを使用しての一つの方法にオーバーロードされたメソッドの束を組み合わせることができます場合、私はその多くのクリーナーを考える
アミットWadhwa

あなたはそれを考えることができます。私はMicrosoftがすべてを正しい方法で行うとは思っていませんが、正確であれば、.NETフレームワークを使用するときにオーバーロードが表示されることはありません.1つの巨大な関数シグネチャ-ol 'VB6のように。
ハードコード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.