関数内のパラメーターの順序に関するベストプラクティスは何ですか?


52

時々(まれに)、適切な量のパラメーターをとる関数を作成することが最適なルートであると思われます。しかし、そうすると、パラメーターの順序をランダムに選択することが多いように感じます。私は通常、最も重要なパラメーターを最初に使用して、「重要度の順に」進みます。

これを行うためのより良い方法はありますか?明確性を高めるパラメーターを並べる「ベストプラクティス」の方法はありますか?


5
名前付きパラメーターにより、これは問題になりません。Pythonはそれを極限までとらえ、調べます。良い例はC#にあります-を呼び出す多くの方法MessageBox.Showです。それも調べてください。
仕事

8
Haskellでは、部分関数アプリケーションの有用性は通常、自然な引数の順序付けを示唆しています。
-tdammers

適切な量​​のパラメーターは何だと思いますか?
クリス

2つ以上のパラメーターに順序付けが適用されると思いますが、2つ以上を考えていました。
ケーシーパットン

3
これはまた、カリー化を直接サポートがある任意の言語の真実である@tdammers
JKを。

回答:


55

一般的に:それを使用します。

関数のテスト、実際のテストを作成します。
何かあなたが実際にその機能をどうしたいと思います

そして、それらを下に置いた順番を確認してください。

同様のことをする機能を既に持っている(または知っている)場合を除きます。
その場合:少なくとも最初の引数については、彼らがすでにやっていることに準拠します。

例えば、それらはすべて最初の引数としてドキュメント/オブジェクト/ファイルポインター/値のシリーズ/座標を取りますか?神のためにそれらの議論に準拠してください

あなたの同僚あなたの将来の自己混同しないでください。


12
「混乱しないように...あなたの将来の自己」は、一般的に良い哲学のように聞こえます。
ジャンヌピンダー

28

いつも同じ優先順位であるとは限りませんが、私は通常これらの規則に従います。今では自動思考プロセスだと思いますが、パブリックAPI設計を除き、考え直しはしません

選択ファンネル

  1. 意味論
  2. 重要性/関連性
  3. 使用頻度
  4. I / Oの懸念

1.セマンティクスファースト

特にOOPでは、アクションまたはメッセージの意味的な意味に基づいてパラメーターを選択します。適切な名前のパラメータを持つ適切な名前のメソッドのシグネチャは次のようにする必要があります。

  • 電話するのが自然だと感じる
  • 意図と行動の観点から自己記述的である。

(これらの理由により、プリミティブの代わりにカスタム型またはエイリアスを使用すると、署名の表現力が向上する場合があります。)

2.次に重要性

最も「重要な」パラメーターが最初に来る(または次...)

3.その後、頻度

頻度も重要です。特に、名前付きパラメーターはないが、位置パラメーターにデフォルト値を設定できる言語では重要です。つまり、パラメーターの順序は変わらず、N番目のパラメーターの既定値を強制する場合は、N + 1パラメーターを設定できないことは明らかです(言語にプレースホルダーパラメーターの概念がある場合を除く) )。

良いニュースは、通常、頻度は重要性に関連しているため、前のポイントと連動していることです。そして、適切なセマンティクスを持つようにAPIを作成するのはおそらくあなた次第です。

4. I / Oを忘れないでください

メソッド/関数が入力を受け取って出力を生成し、後者が「return」ステートメントを介して「return」または「exception system」を使用して「スロー」されない場合、渡すオプションが残っています他のパラメーター(または入力パラメーター)を使用して、呼び出し元に値を返します。これはセマンティクスに関連しており、ほとんどの場合、最初のパラメーターで出力を定義し、最後のパラメーターで出力を受け取るのが理にかなっています。

さらに、パラメーターを減らしてセマンティクスを最大化する別のアプローチは、機能的なアプローチを使用するか、Builderパターンを定義することです。したがって、入力を明確に積み重ね、出力を定義し、必要なときにそれらを取得できます。

(グローバル変数については言及していません。なぜ使用するのですか?)


考慮すべき事項

  • 使いやすさ

    あなたはZJRの続く場合は、上記のほとんどは自然に表示されますアドバイス使用それを!

  • リファクタリングを検討する

    パラメーターの順序について心配する場合、おそらくこの心配は、上記と、APIの設計が不適切であることに原因があることがわかります。パラメーターが多すぎる場合は、おそらくコンポーネント化/モジュール化およびリファクタリングが可能です。

  • パフォーマンスを考慮する

    一部の言語の実装は、パラメーターを使用するときにランタイムメモリ管理に非常に重要な影響を与えることに注意してください。したがって、多くの言語のスタイルブックがパラメーターリストをシンプルかつ短く保つことを推奨する理由。たとえば、最大4つのパラメーター。理由を理解するための演習として残しておきます。

  • Clean Codeの推奨事項に関するBevanの回答と言及は、間違いなく関連性があります!


18

パラメーターの順序付けを気にすることは、間違ったことを心配することであると、私は敬意をもって提出します。

ボブおじさんの本「Clean Code」では、説得力のあることに、メソッドには2つ以上の引数を含めることはできません。この場合、順序は明白または重要ではありません。

不完全ではありますが、私はボブおじさんのアドバイスに従おうとしています-そしてそれは私のコードを改善しています。

メソッドより多くの情報を必要とするようなまれなケースでは、パラメーターオブジェクトを導入することをお勧めします。通常、これは私のアルゴリズムの鍵となる新しい概念(オブジェクト)を発見するための最初のステップであると思います。


私は間違いなくあなたに同意します!私の最初の声明は、これが私にとって典型的なものではないという点に到達することを目的としていました。しかし、私が本当にいくつかのパラメーターを渡す必要があるとわかった場合、プログラム全体をリファクタリングすることは価値がありません、注文について疑問に思います。
ケーシーパットン

3
PHP 。申し訳ありませんが、パラメータの順序を気にしないでくださいと言っていましたか?
クレイジュ

その場合、ちょうど同じ数の引数を取るパラメーターオブジェクトのコンストラクターがありませんか?
確実に

いいえ-パラメータオブジェクトは、より読みやすい方法で複数のステートメントにわたって「構築」できるためです。
ベヴァン

2
@Bevan:これは非常に議論の余地があります。この方法でオブジェクトを構築するということは、それらがもはや不変になれないことを意味します。ただし、可能な限りオブジェクトを不変に保つことは、保守性を高めるもう1つの優れた方法です。
-tdammers

10

INパラメーターを最初に、OUTパラメーターを2番目に配置しようとしました。いくつかの自然な順序でもありますが、例えばcreatePoint(double x, double y)に強くpreferrableですcreatePoint(double y, double x)


5
時には、逆の方が良い場合があります。たとえば、常に1つのOUT引数と可変数のin引数がある場合などですaddAllTo(target, something1, something2)
-maaartinus

私は同じルールに従いますが、可能な限りOUTパラメーターを避け、ほとんどの優秀なプログラマーも避けようとします。したがって、この推奨事項が実際にOPを支援する機能の数は、かなり少なくする必要があります。
Doc Brown

7
@DocBrown優秀なプログラマーを避けようとするべきではありません。
RyanfaeScotland

@RyanfaeScotland:くそー、投稿する前にコメントを2回読む必要があります(少なくとも5分以内にコメントを変更できます);
Doc Brown

6

この特定のトピックに関する文書化された「ベストプラクティス」を見たことはありませんが、私の個人的な基準は、使用されているメソッドに表示される順序で、またはメソッドがデータレイヤーへのパススルーdbスキーマまたはデータレイヤーメソッドに表示される順序でリストします。

また、メソッドのオーバーロードが複数ある場合、一般的な方法は、すべての(またはほとんどの)メソッドに共通のパラメーターからリストすることで、各メソッドオーバーロードのように各メソッドが最後に追加されることに注意してください:

void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }


3

多くの場合、const最初にパラメーター(つまり、値で渡すパラメーター)を配置し、次に参照で渡すパラメーターを配置するC / C ++の規則に従います。これは必ずしも関数を呼び出す正しい方法ではないかもしれませんが、各コンパイラがパラメーターを処理する方法に関心がある場合は、パラメーターを管理する規則および/またはスタックにプッシュされる順序について次のリンクを参照してください。

http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx

http://en.wikipedia.org/wiki/Calling_convention


興味のある他のリンクは msdn.microsoft.com/en-us/library/984x0h58%28v=vs.71%29.aspxです 。再帰関数については、次のリンクをご覧くださいpublications.gbdirect.co.uk/c_book/chapter4/… 忘れていたわけではありませんが、新しいユーザーであるため、3つ以上のリンクがあるコメントを投稿することはできません。
ビル

1

私は通常、「cyprticに見えないもの」のパラメーターの順序を使用します。メソッド/関数の定義に行く必要がある回数が少ないほど良いです。そして、小さなツールチップがポップアップ(VS)されると、それがさらに簡単になります。

パラメータの行と行がある場合は、異なる設計を検討することをお勧めします。一歩下がって、それをより多くの関数/メソッドに分割する方法を確認してください。ただのアイデアですが、関数に12個のパラメーターがある場合、ほとんどの場合パラメーターの問題ではなく、設計の問題です。


2
「cyprtic」:要点を説明するのに最適な方法。
ベヴァン

2
@Bevan、これまでタイプミスはありませんでしたか?

1
cyprticを書くのはよくできたので、タイプミスがありました。それを元に戻してください。それは事故であっても、あなたの主張を助けるのに役立ちます。
ベヴァン

1
@Bevan、ハハ、オーケー、あなたの言っていることがわかります。いい視点ね!変更後=)

1

時々(まれに)、適切な量のパラメーターをとる関数を作成することが最適なルートであると思われます。

多くの場合、いくつかのパラメーターを使用することは、この方法でSRPに違反するという明確な指標です。多くのパラメーターを必要とするメソッドは、1つのことだけを行うことはほとんどありません。除外は、数学関数または構成方法である場合があり、実際にはいくつかのパラメーターが必要です。悪魔が聖水を避けるので、私は複数のパラメーターを避けます。メソッド内で使用するパラメーターが多いほど、メソッドが(あまりにも)複雑になる可能性が高くなります。複雑さが増すということは、保守が難しくなり、あまり望ましくないことを意味します。

しかし、そうすると、パラメーターの順序をランダムに選択することが多いように感じます。私は通常、最も重要なパラメーターを最初に使用して、「重要度の順に」進みます。

原則として、ランダムに選択しています。もちろん、パラメータAはパラメータBよりも関連性が高いと考えるかもしれません。ただし、Bが最も適切なパラメーターであると考えるAPIのユーザーには当てはまらない可能性があります。そのため、順序を注意深く選んだとしても、他の人にとってはランダムに見えるかもしれません。

これを行うためのより良い方法はありますか?明確性を高めるパラメーターを並べる「ベストプラクティス」の方法はありますか?

いくつかの方法があります。

a)些細なケース:複数のパラメーターを使用しないでください。

b)指定していないので、どの言語を選択したか、名前付きパラメーターを持つ言語を選択した可能性があります。これは、パラメーターの順序付けの重要性を緩和することができる素晴らしい構文糖です:fn(name:"John Doe", age:36)

すべての言語でこのような機能が使用できるわけではありません。それでは何ですか?

c)ディクショナリ/ハッシュマップ/連想配列をパラメータとして使用できます。たとえば、Javascriptでは次のことが可能です:fn({"name":"John Doe", age:36})(b)からそれほど遠くありません。

d)もちろん、Javaのような静的に型付けされた言語を使用する場合。Hashmapを使用することもできますがHashMap<String, Object>、パラメーターの型が異なる(およびキャストする必要がある)場合は、型情報が失われます(たとえば、使用時)。

次の論理的なステップはObject、適切なプロパティまたは構造体のようなより軽量なもの(Javaを使用している場合)を渡すことです(たとえば、C#またはC / C ++を記述する場合)。

経験則:

1)ベストケース-メソッドにパラメーターは必要ありません

2)良いケース-メソッドには1つのパラメーターが必要です

3)許容可能なケース-メソッドには2つのパラメーターが必要

4)その他のすべてのケースはリファクタリングする必要があります


0

多くの場合、パラメーターとしての複雑なオブジェクトの方が優れています。ほとんどのプラットフォームで機能する、名前の付いたパラメーターの貧乏人向けのバージョンです。そして、起動する動作を備えたパラメータへの扉を開きます。

してはいけないことのほとんどの例については、PHPの標準ライブラリのドキュメントを読んでみてください。


0

私は通常ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)、特定の慣行ではなく、「感情」(と見ることができる)に従って重要性と使用頻度を組み合わせた尺度ではなく、最初に必要な順序で注文します。

しかし、他の人が指摘したように、これを問題にする根本的な問題は、あまりにも多くのパラメーターを使用することであると思います(IMHO、3を超えるものは多すぎます)。あります興味深い記事レベッカ・マーフィさんのブログでそのことについては。

引数が1〜3個しかない場合、正しい順序付けは非常に明白であり、正しいことを「感じる」だけだと思います。


0

@Wyatt Barnettsの答えと同様に、メソッドのいくつかのパラメーターまたは非常に明示的なパラメーター以外のものは、代わりにオブジェクトを渡すことをお勧めします。通常、これは更新/保守が簡単で、読みやすく、順序付けを気にする必要がありません。また、メソッドのパラメーターが多すぎるとコードの臭いがし、修正に役立つ一般的なリファクタリングパターンがあります。

明示的な例:

public int add(int left, int right)
{
  return left + right;
}

これはかなり明確に定義された例であり、加算は可換であるため(順序は関係ありません)、そのまま使用します。

ただし、より複雑なものを追加する場合:

public SomeComplexReturnValue Calculate(int i, float f, string s, object o)
{
  // do work here
}

になるでしょう:

public class SomeComplexInputForCalculation
{
  public int i; 
  public float f;
  public string s; 
  public object o;
}

public SomeComplexReturnValue Calculate(SomeComplexInputForCalculation input)
{
  // do work here
}

お役に立てれば...


0

あなたがカレーが恩恵を受ける可能性が高いと思うどんな方法でもそれを注文してください。たとえば、関数パラメーターが最初です。


0

「重要な最初の」は、全体を意味しません。いくつかの規則があります。

呼び出し元のオブジェクト(多くの場合、名前付き送信者)を渡すと、それが最初になります。

リストにはある程度の流encyさがあるはずです。つまり、読む前に引数が何であるかを知る必要があります。例:

CopyFolder(string path、bool recursive);

再帰を最初に置いた場合、コンテキストがまだないため、混乱を招きます。すでにコピー(1)、フォルダー(2)についてである場合、引数再帰は意味を成し始めます。

また、これにより、IntelliSenseのような機能がうまく機能します。ユーザーは、引数を入力しながら学習し、メソッドとその機能の理解を深めます。同様に、オーバーロードは、等しいパーツに対して同じ順序を維持する必要があります。

その後、この点で「等しい」引数があることに気付く場合があり、順序を引数のタイプに依存させたいと思うかもしれません。行にいくつかの文字列があり、次にいくつかのブール値があるほうが見栄えがいいからです。あるレベルでは、これはスキルではなく芸術になります。

単一の引数で終わるために、すべての引数をオブジェクトにラップする必要があるというステートメントはあまり気にしません。それはただあなたを欺くだけです(メソッドをそれほど複雑にしません、それでもこれらの引数をすべて持っています、あなたはそれらを隠しました)。メソッドからメソッドへのセットを数回渡す場合、これはまだ便利かもしれませんが、リファクタリングははるかに簡単になりますが、デザイン的にはあなたが違いを生じているふりをしているだけです。何かを表す意味のあるオブジェクトになるのではなく、メソッドの宣言のリストと変わらない単なる引数の集まりになります。それはボブおじさんを幸せにしません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.