228

ルーチンにはパラメーターを含めることができますが、これはニュースではありません。パラメーターは必要な数だけ定義できますが、パラメーターが多すぎると、ルーチンの理解と保守が難しくなります。

もちろん、回避策として構造化変数を使用することもできます。これらのすべての変数を 1 つの構造体に入れ、それをルーチンに渡します。実際、構造体を使用してパラメーター リストを単純化することは、Steve McConnell がCode Completeで説明している手法の 1 つです。しかし、彼が言うように:

注意深いプログラマーは、論理的に必要以上にデータをバンドルすることを避けます。

そのため、ルーチンのパラメーターが多すぎる場合や、構造体を使用して大きなパラメーター リストを偽装している場合は、おそらく何か問題があります。つまり、カップリングを緩めたままにしていません。

私の質問は、いつパラメーター リストが大きすぎると見なすことができるかということです。5つ以上のパラメータは多すぎると思います。どう思いますか?

4

34 に答える 34

162

憲法修正第 1 条が言論の自由を保証しているにもかかわらず、何かが規制できるほどわいせつと見なされるのはいつですか? ポッター・スチュワート判事によれば、「見ればわかる」。ここでも同じです。

プロジェクトの規模や範囲だけでなく、モジュールのレベルまで変わってしまうと思うので、このような厳格なルールを作るのは嫌いです。メソッドが何を行っているか、またはクラスが何を表現するかによって、2 つの引数が多すぎて、カップリングが多すぎる兆候である可能性は十分にあります。

最初に質問をし、あなたがしたのと同じようにあなたの質問を限定することによって、あなたはこれらすべてを本当に知っていることをお勧めします. ここでの最善の解決策は、確固たる数字に頼るのではなく、同僚間での設計レビューやコード レビューに目を向け、凝集度が低く密結合している領域を特定することです。

同僚に自分の作品を見せることを恐れないでください。恐れている場合は、おそらくコードに何か問題があり、すでにそれを知っているというより大きな兆候です。

于 2008-10-06T16:25:52.597 に答える
124

一部のパラメーターが冗長である場合にのみ、関数に含めることができるパラメーターが多すぎます。すべてのパラメーターを使用する場合、関数には正しい数のパラメーターが必要です。このよく使われる関数を見てください:

HWND CreateWindowEx
(
  DWORD dwExStyle,
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWndParent,
  HMENU hMenu,
  HINSTANCE hInstance,
  LPVOID lpParam
);

これは12個のパラメーター(x、y、w、hを長方形としてバンドルした場合は9個)であり、クラス名から派生したパラメーターもあります。これをどのように減らしますか?数をもっと減らしたいですか?

パラメータの数に煩わされることはありません。論理的で十分に文書化されていることを確認し、インテリセンス*が役立つようにしてください。

*他のコーディングアシスタントも利用できます!

于 2008-10-06T16:37:25.257 に答える
106

Clean Codeで、Robert C. Martin はこのテーマに 4 ページを割きました。要点は次のとおりです。

関数の引数の理想的な数はゼロ (ニラディック) です。次に 1 つ (モナディック) が続き、2 つ (ダイアディック) がすぐ後に続きます。3 つの引数 (triadic) は、可能な限り避ける必要があります。3 を超える (ポリアディック) には、非常に特別な正当化が必要です。とにかく使用しないでください。

于 2008-10-06T16:25:53.453 に答える
79

過去に使用した一部のコードでは、あまりにも多くのパラメーターを渡すのを避けるためにグローバル変数を使用していました。

お願い、それはやめて!

(いつもの。)

于 2008-10-06T16:28:52.417 に答える
38

署名のパラメーターを頭の中で数えて呼び出しに一致させる必要がある場合は、リファクタリングを行うときです。

于 2008-10-06T16:19:35.667 に答える
31

ご回答いただきありがとうございます。

  • (私と同じように) 5 つのパラメーターがコードの健全性にとって適切な制限であると考えている人を見つけたのは少し驚きでした。

  • 一般的に、3 から 4 の間の制限が経験則として適切であることに同意する傾向があります。人々は通常、4 つ以上のものを数えるのが苦手なので、これは合理的です。

  • Milanが指摘するように、平均して、人は一度に多かれ少なかれ 7 つのことを頭に入れておくことができます。しかし、ルーチンを設計/維持/研究する際には、パラメーターだけでなく、より多くのことを念頭に置く必要があることを忘れてはならないと思います。

  • ルーチンには必要な数の引数が必要であると考える人もいます。同意しますが、いくつかの特定のケース (OS API の呼び出し、最適化が重要なルーチンなど) についてのみです。可能であれば、これらの呼び出しのすぐ上に抽象化のレイヤーを追加して、これらのルーチンの複雑さを隠すことをお勧めします。

  • ニックはこれについて興味深い考えを持っています。彼のコメントを読みたくない場合は、要約します。一言で言えば、状況によって異なります

    プロジェクトの規模や範囲だけでなく、モジュールのレベルまで変わってしまうと思うので、このような厳格なルールを作るのは嫌いです。メソッドが何を行っているか、またはクラスが何を表現するかによって、2 つの引数が多すぎて、カップリングが多すぎる兆候である可能性は十分にあります。

    ここでの教訓は、同僚にコードを見せることを恐れず、彼らと話し合い、「結束力が低く、密結合している領域を特定する」ことです

  • 最後に、wnoiseは Nick に大いに同意し、彼の風刺的な貢献を、プログラミング技術のこの詩的なビジョン(以下のコメントを参照) で締めくくっていると思います。

    プログラミングはエンジニアリングではありません。コードの編成は芸術です。人的要因に依存するためです。人的要因は、厳密なルールのコンテキストに大きく依存します。

于 2008-10-06T21:14:36.770 に答える
16

この回答は、オブジェクト指向言語を想定しています。使用していない場合は、この回答をスキップしてください(つまり、これは言語にとらわれない回答ではありません。

3 つ以上のパラメーター (特に組み込み型/オブジェクト) を渡す場合、「多すぎる」ということではなく、新しいオブジェクトを作成する機会を逃している可能性があります。

複数のメソッドに渡されるパラメーターのグループを探します。2 つのメソッドに渡されるグループでさえ、そこに新しいオブジェクトがあることがほぼ保証されます。

次に、機能を新しいオブジェクトにリファクタリングしますが、それがコードと OO プログラミングの理解の両方にどれほど役立つかは信じられないでしょう。

于 2008-10-06T16:27:43.950 に答える
13

単なる数以外の考慮事項があるようですが、ここに思いつくものをいくつか示します。

  1. 機能の主な目的と 1 回限りの設定との論理関係

  2. それらが単なる環境フラグである場合、バンドルは非常に便利です

于 2008-10-06T16:22:34.723 に答える
12

Alan Perlis の有名なプログラミング エピグラム (ACM SIGPLAN Notices 17(9)、1982 年 9 月) の 1 つは、「10 個のパラメーターを持つプロシージャーがある場合、おそらく一部を見逃している」と述べています。

于 2008-10-06T17:59:40.923 に答える
11

CodeCompleteのSteveMcConnellによる

ルーチンのパラメーターの数を約7つに制限します

于 2008-11-25T23:48:44.693 に答える
9

私の場合、IDE でリストが 1 行を超えると、1 つのパラメーターが多すぎます。アイコンタクトを崩さずに、すべてのパラメーターを 1 行で表示したいと考えています。しかし、それは私の個人的な好みです。

于 2008-10-06T16:17:46.870 に答える
9

おおむね 5 に同意しますが、もっと必要な状況があり、それが問題を解決する最も明確な方法である場合は、もっと使用します。

于 2008-10-06T16:18:13.483 に答える
8

短期記憶の7つのこと?

  1. 関数名
  2. 関数の戻り値
  3. 機能の目的
  4. パラメータ 1
  5. パラメータ 2
  6. パラメータ 3
  7. パラメータ 4
于 2010-12-18T03:57:59.627 に答える
7

Worst 5 Code Snippetsで、2 つ目の「Is this a constructor」を確認します。37 ⋅ 4 ≈ 150 以上のパラメータがあります。

ここで、プログラマーがこのコンストラクターを作成しました [... 一部の人は、これは大きなコンストラクターだと思うかもしれませんが、彼は Eclipse 自動コード生成ツールを使用していました[.] いいえ、このコンストラクターには、私が発見した小さなバグがありました。このコンストラクターは手書きで書かれたと結論付けます。(ちなみに、これはコンストラクターの上部のみであり、完全ではありません)。

150 以上のパラメーターを持つコンストラクター

于 2010-03-02T08:07:55.030 に答える
6

必要以上に1つ。私はglibであるという意味ではありませんが、必然的にかなりの数のオプションを必要とするいくつかの関数があります。例えば:

void *
mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset);

6つの議論があり、それらのすべてが不可欠です。さらに、それらをバンドルすることを正当化するための共通のリンクはありません。「structmmapargs」を定義できるかもしれませんが、それはさらに悪いことです。

于 2008-10-06T16:35:44.337 に答える
5

Perl Best Practicesによると、3 は問題ありませんが、4 は多すぎます。あくまでも目安ですが、当店ではこれを徹底しております。

于 2008-10-06T16:18:42.080 に答える
5

私は5つのパラメータでパブリック関数の制限を自分で描きます。

IMHO、長いパラメーター リストは、コード内のいくつかの特定の場所からのみ呼び出されることを意図したプライベート/ローカル ヘルパー関数でのみ受け入れられます。そのような場合、多くの状態情報を渡す必要があるかもしれませんが、あなた (またはコードを保守し、モジュールの基礎を理解する必要がある人) だけが気にする必要があるため、読みやすさはそれほど大きな問題ではありません。その関数を呼び出します。

于 2008-10-06T16:24:29.027 に答える
5

あなたが考慮すべき関連する質問は、ルーチンがどれほどまとまりがあるかということです. パラメータの数が多いということは、ルーチン自体がやろうとしていることを示しているにおいかもしれません。厳密で高速な数のパラメーターはおそらく不可能であることに同意しますが、凝集度の高いルーチンはパラメーターの数が少ないことを意味すると思います。

于 2008-10-28T13:42:38.057 に答える
4

パフォーマンスの観点から指摘することの1つは、メソッドにパラメーターを渡す方法によっては、各パラメーターをコピーしてスタックに配置する必要があるため、値で多くのパラメーターを渡すとプログラムの速度が低下することです。

単一のクラスを使用してすべてのパラメーターを網羅すると、参照によって渡される単一のパラメーターがエレガントでクリーンになり、より高速になるため、より適切に機能します。

于 2010-10-26T07:46:48.543 に答える
4

パラメータリストの長さの制限は、もう1つの制限です。そして制限とは、適用される暴力を意味します。面白そうに聞こえますが、プログラミングをしているときでも非暴力的である可能性があります。コードにルールを指示させるだけです。多くのパラメーターがある場合、関数/クラスメソッドの本体はそれらを利用するのに十分な大きさになることは明らかです。また、大きなコードスニペットは通常、リファクタリングして小さなチャンクに分割できます。したがって、リファクタリングされた小さなコードに分割されるため、無料のボーナスとして多くのパラメーターを持つことに対する解決策が得られます。

于 2008-10-06T16:34:53.357 に答える
4

一般的な経験則として、3 つのパラメーターで停止します。代わりに、パラメーターの配列または構成オブジェクトを渡すときが来ました。これにより、API を変更せずに将来のパラメーターを追加することもできます。

于 2008-10-06T16:24:28.743 に答える
3

私によると、あなたが4またはいくつかの固定数を超える場合があるかもしれません。気をつけるべきことは

  1. メソッドの処理が多すぎるため、リファクタリングする必要があります。
  2. コレクションまたはデータ構造の使用を検討することをお勧めします。
  3. クラスの設計を再考してください。おそらく、いくつかのものを渡す必要はありません。

使いやすさやコードの読みやすさの観点から、メソッドシグネチャを「ワードラップ」する必要がある場合は、無力感を感じてシグネチャを小さくするためのあらゆる努力が必要な場合を除いて、停止して考える必要があると思います。検索結果はありません。過去と現在のいくつかの非常に優れたライブラリは、4〜5台以上の乳母車を使用しています。

于 2008-11-25T23:41:07.923 に答える
3

私の経験則では、呼び出しを見て、それが何をするかを伝えるのに十分な長さのパラメーターを記憶できる必要があります。したがって、メソッドを見てからメソッドの呼び出しに戻って、どのパラメーターが何をするかを覚えていない場合は、多すぎます。

私にとっては約5に相当しますが、それほど明るくはありません. あなたのマイレージは異なる場合があります。

パラメータを保持するプロパティを持つオブジェクトを作成し、設定した制限を超えた場合にそれを渡すことができます。Martin Fowler のRefactoring book と、メソッド呼び出しをより簡単にする方法に関する章を参照してください。

于 2009-10-24T13:08:39.860 に答える
1

関数が呼び出される頻度に基づいて答えます。

1 回しか呼び出されない init 関数の場合は、10 個以上のパラメーターを必要としますが、気にする必要はありません。

フレームごとに何度も呼び出される場合は、構造体を作成してポインターを渡す傾向があります。これは、高速になる傾向があるためです (構造体を毎回再構築しないと仮定します)。

于 2008-10-07T00:28:28.080 に答える
1

1 つのルーチンに 7 ~ 10 個のパラメーターがある場合、それらを新しいクラスにバンドルすることを検討します、そのクラスが getter と setter を持つフィールドの束にすぎない場合はそうしません。新しいクラスは値をシャッフルする以外のことをしなければなりませんアウト。それ以外の場合は、長いパラメーター リストを我慢したいと思います。

于 2008-10-06T17:02:08.637 に答える
1

Clean Code での Robert Martin の引用 (上記で引用)に同意します: パラメータが少ないほど良い。5 ~ 7 個を超えるパラメーターとメソッド呼び出しは、理解するのがかなり難しくなります。一部のパラメーターがオプションである (したがって null 値を取る) 場合、またはすべてのパラメーターが同じ型である場合 (どのパラメーターがどれであるかを判断するのがさらに難しくなります) の場合、事態は特に悪化します。パラメーターを Customer や Account などのまとまりのあるドメイン オブジェクトにまとめることができれば、コードの操作がより快適になります。

エッジケースがあります:論理セットを形成する可変数のパラメーターを取るメソッド呼び出しがある場合、より多くのパラメーターを持つ認知オーバーヘッドが少なくなります。たとえば、再試行間のミリ秒数に関して、HTTP 要求の再試行回数を指定するメソッドが必要になる場合があります。1 秒、2 秒、3 秒間隔での 3 回の再試行は、次のように指定できます。

retries(1000, 2000, 3000)

この限られたケースでは、呼び出しにパラメーターを追加しても、精神的な過負荷はそれほど増加しません。

もう 1 つの考慮事項は、言語が名前付きパラメーター リストをサポートしており、オプションのパラメーターを省略できるかどうかです。より大きな名前付きパラメーター リストは、より大きな名前のないパラメーター リストよりも理解しやすくなります。

しかし、私はパラメータを多くするのではなく、少なくする側で間違いを犯します。

于 2009-11-17T06:50:13.823 に答える
1

作業している環境に大きく依存します。たとえば、javascript を考えてみましょう。JavaScript でパラメーターを渡す最良の方法は、キーと値のペアを持つオブジェクトを使用することです。これは、実際にはパラメーターが 1 つしかないことを意味します。他のシステムでは、スイート スポットは 3 または 4 になります。

結局のところ、それはすべて個人的な好みに要約されます。

于 2008-10-06T16:22:38.843 に答える
1

ガイドラインとしては 3 は問題ありませんが、4 は多すぎることに同意します。3 つ以上のパラメーターを使用すると、必然的に複数のタスクを実行することになります。複数のタスクを別々のメソッドに分割する必要があります。

ただし、私が取り組んだ最新のプロジェクトを見ると、例外が多く、ほとんどの場合、3 つのパラメーターに到達するのは困難です。

于 2008-10-06T16:25:02.003 に答える
1

平均して、人は一度に 7 +/- 2 個のことを頭に入れておくことができるということは、知られている事実です。私はその原則をパラメーターで使用するのが好きです。プログラマーが全員平均以上の知的な人々であると仮定すると、10 人以上というのは多すぎると言えます。

ところで、パラメーターが何らかの形で似ている場合は、それらを構造体やクラスではなくベクターまたはリストに入れます。

于 2008-10-06T17:38:58.343 に答える
1

Amazon で有名な Jeff Bezos 氏によると、ピザ 2 枚分しか食べられないそうです。

于 2008-10-07T00:45:09.093 に答える
0

IMO、長いパラメータリストの正当性は、データまたはコンテキストが本質的に動的であるということです。printf()について考えてみてください。varargsを使用する良い例。このような場合を処理するためのより良い方法は、ストリームまたはxml構造を渡すことです。これにより、パラメーターの数が最小化されます。

マシンは確かに多くの引数を気にしませんが、開発者は、メンテナンスオーバーヘッド、単体テストケースの数、および検証チェックについても考慮します。設計者は長い引数リストも嫌いです。引数が多いほど、変更が行われるたびにインターフェイス定義が変更されることを意味します。上記の観点からの結合/凝集度に関する質問。

于 2008-10-06T16:49:21.330 に答える
0

オーバーロードが 2 ~ 4 である限り、必要に応じて高くするのが良いと思います。

于 2008-10-06T16:24:56.670 に答える
0

実際の数は、関数のコンテキストで何が論理的に意味があるかに本当に依存すると思います。約 4 ~ 5 個のパラメーターが混雑し始めることに同意します。

フラグを設定する場合、この状況を処理する優れた方法は、値を列挙してそれらを OR することです。

于 2008-10-06T16:25:32.207 に答える