時々(まれに)、適切な量のパラメータをとる関数を作成するのが最善の方法のようです。ただし、その場合、パラメーターの順序をランダムに選択しているように感じることがよくあります。私は通常、「重要度の順序」で、最も重要なパラメーターを最初に使用します。
これを行うより良い方法はありますか?わかりやすくするためにパラメータを並べる「ベストプラクティス」の方法はありますか?
一般的に:使用する。
関数のテスト、つまり実際のテストを作成します。
何か実際にその関数で実行したい。
そして、それらを下に置いた順序で確認してください。
同様のことをするいくつかの関数をすでに持っている(または知っている)場合を除きます。
その場合:conformは、少なくとも最初の引数については、すでに行っていることを実行します。
例最初の引数としてdocument/object/file-pointer/series-of-values/coordinatesを使用しますか?神のためにこれらの引数に準拠。
同僚の混乱と将来の自己の混乱を避けます。
私は通常これらのルールに従いますが、常に同じ優先順位を持つわけではありません。今は自動の思考プロセスだと思います。私はパブリックAPIの設計を除いて、考えすぎないでください。
特にOOPでは、アクションまたはメッセージの意味的意味に基づいてパラメーターを選択する。適切な名前のパラメータを持つ適切な名前のメソッドのシグネチャは、次のようにする必要があります。
(これらの理由により、プリミティブの代わりにカスタムタイプまたはカスタムエイリアスを使用すると、署名の表現力が高まる場合があります。)
最も「重要な」パラメータが最初に来る(または次が...)
頻度も重要です。特に、名前付きパラメーターがなく、定位置パラメーターにデフォルト値を設定できる言語ではそうです。つまり、パラメーターの順序は変化せず、N番目のパラメーターのデフォルト値を強制したい場合は、N + 1パラメーターを設定できないことを意味します(言語にプレースホルダーパラメーターの概念がある場合を除く) )。
あなたにとっての良いニュースは、通常、頻度は重要性に関連しているので、それは前のポイントと関連しています。そして、適切なセマンティクスを持つAPIを作成するのはおそらくあなた次第です。
メソッド/関数が入力を受け取り、出力を生成し、後者が(returnステートメントを介して)「返される」ことも、(例外システムを使用して)「スローされる」こともない場合は、渡すオプションがあります。他のパラメーター(または入力パラメーター)を使用して、値を呼び出し元に返します。これはセマンティクスに関連しており、ほとんどの場合、最初のパラメーターで出力を定義し、最後のパラメーターで出力を受け取ることは理にかなっています。
さらに、パラメーターを減らしてセマンティクスを最大化する他のアプローチは、機能的アプローチを使用するか、または Builderパターン を定義することです。これにより、入力を明確に積み重ね、出力を定義し、それらを取得できます。必要なときに。
(グローバル変数については触れないことに注意してください。なぜそれを使用するのですか?)
使いやすさ
上記のほとんどは、ZJRの advice に従うと自然に表示されます:se It!
リファクタリングを検討
パラメータの順序付けについて心配している場合、おそらくこの心配の原因は上記にあり、APIの設計が不適切であることにあります。 パラメータが多すぎる場合、おそらくコンポーネント化/モジュール化され、リファクタリングされる可能性があります。
パフォーマンスを検討
一部の言語の実装では、パラメータを使用するときにランタイムメモリ管理に非常に重要な影響が生じることに注意してください。したがって、なぜ多くの言語のスタイルブックでは、パラメーターリストをシンプルで短いものにすることを推奨していますなのか。たとえば、最大4つのパラメータで。その理由を理解するための演習として残しておきます。
Bevanの answer と Clean Code の推奨事項の言及も間違いなく関連性があります!
パラメータの順序付けについての心配は間違ったことについての心配であると私は敬意を表します。
ボブおじさんの本「 Clean Code 」では、彼は説得力のある方法で、メソッドに2つを超える引数を設定することはできません。これが当てはまる場合、順序付けは明白であるか重要ではありません。
しかし、私はボブおじさんの助言に完全に従おうとしていますが、コードが改善されています。
メソッドがより多くの情報をrequire要求するように思われるまれなケースでは、 パラメータオブジェクト を導入することをお勧めします。通常、これは私のアルゴリズムの鍵となる新しい概念(オブジェクト)の発見に向けた最初のステップです。
INパラメータを最初に、OUTパラメータを2番目に配置しようとしています。自然な順序付けもあります。 createPoint(double x, double y)
はcreatePoint(double y, double x)
よりも強く推奨されます。
私はこの特定のトピックに関して文書化された「ベストプラクティス」を見たことはありませんが、私の個人的な基準は、それらが使用されているメソッドに現れる順序で、またはメソッドがデータレイヤーへのパススルーデータベーススキーマまたはデータレイヤーメソッドに表示される順序で一覧表示します。
また、メソッドのオーバーロードが複数ある場合、一般的な方法は、すべての(またはほとんどの)メソッドに共通のパラメーターから始めて、各メソッドのオーバーロードの最後にそれぞれの異なるメソッドを追加して、それらをリストすることです。 :
void func1(string param) { }
void func2(string param, int param2) { }
void func3(string param, string param3) { }
void func3(string param, int param2, string param3) { }
順序:入力、出力、オプションのパラメーター。
私はよくconst
パラメーター(つまり、値で渡すパラメーター)を最初に配置し、次に参照で渡すパラメーターを配置するというC/C++の慣例に従います。これは必ずしも関数を呼び出す正しい方法ではないかもしれませんが、各コンパイラーがパラメーターを処理する方法に興味がある場合は、以下のリンクを参照して、ルールを管理するルールや、パラメーターがスタックにプッシュされる順序を確認してください。
http://msdn.Microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
時々(まれに)、適切な量のパラメータをとる関数を作成するのが最善の方法であると思われます。
多くの場合、いくつかのパラメーターを使用すると、このメソッドの [〜#〜] srp [〜#〜] に違反することを示す明確な指標になります。多くのパラメーターを必要とするメソッドは、のみを実行することはほとんどありません。除外は、数学関数または構成メソッドであり、実際にはいくつかのパラメーターが必要です。悪魔が聖水を避けるので、私は複数のパラメーターを避けます。メソッド内で使用するパラメーターが多いほど、メソッドが(あまりに)複雑になる可能性が高くなります。複雑さが増すほど、メンテナンスが難しくなり、望ましくありません。
ただし、その場合、パラメーターの順序をランダムに選択しているように感じることがよくあります。私は通常、最も重要なパラメーターを最初に、「重要度の順序」で進みます。
原則として、ランダムにを選択しています。もちろん、パラメータ[〜#〜] a [〜#〜]はパラメータ[ 〜#〜] b [〜#〜];しかし、[〜#〜] b [〜#〜]が最も関連性の高いパラメーターであると考えるAPIのユーザーには当てはまらない場合があります。したがって、順序を選択する際に注意を払っていたとしても、他の人にとってはrandomに見えるかもしれません。
これを行うより良い方法はありますか?わかりやすくするためにパラメータを順序付ける「ベストプラクティス」の方法はありますか?
いくつかの方法があります:
a)自明なケース:複数のパラメーターを使用しないでください。
b)指定しなかったように、選択した言語は、名前付きパラメーターで言語を選択した可能性があります。これはニース構文糖であり、パラメータの順序付けの重要性を緩めることができます:fn(name:"John Doe", age:36)
すべての言語がそのようなすばらしいことを許可するわけではありません。それでは何ですか?
c)Dictionary/Hashmap/Associative Arrayをパラメーターとして使用できます。 JavaScriptは以下を許可します:fn({"name":"John Doe", age:36})
これは(b)からそれほど離れていません。
d)もちろん、Javaのような静的に型付けされた言語で作業する場合。 Hashmapを使用できますが、型情報が失われます(たとえば、HashMap<String, Object>
)パラメータの型が異なる場合(およびキャストする必要がある場合)。
次の論理的なステップは、適切なプロパティまたはstructのようなより軽量なObject
(Javaを使用している場合)を渡すことです。 (例えばC#やC/C++を書いた場合)。
経験則:
1)最良のケース-メソッドにはnoパラメータが必要です
2)良いケース-メソッドには1つのパラメーターが必要
3)許容できるケース-メソッドには2つのパラメーターが必要
4)他のすべてのケースはリファクタリングする必要があります
私は通常、「cyprticに見えないもの」パラメータの順序を使用します。メソッド/関数の定義に行く必要がある回数が少ないほど良いです。そして、それらが何のために使用されているかを説明する名前付きパラメーターを持っているのはいいことです。そうすれば、小さなツールチップがポップアップ(VS)したときに、さらに簡単になります。
線とパラメータの線がある場合は、別の設計を検討することをお勧めします。一歩下がって、それをより多くの関数/メソッドに分解する方法を見てください。アイデアにすぎませんが、関数に12個のパラメーターがある場合、ほとんどの場合、パラメーターの問題ではなく、デザインの問題です。
多くの場合、パラメータとしての複雑なオブジェクトの方が優れています-ほとんどのプラットフォームで機能する名前付きパラメータの貧弱な人のバージョン。そして、起動する動作を持つパラメータへの扉を開きます。
PHPの標準ライブラリのドキュメントを読んでみてください。
「重要な最初」は、全体を意味するものではありません。いくつかの慣習があります。
呼び出し元オブジェクト(多くの場合、送信者と呼ばれる)を渡すと、最初にそれが渡されます。
リストにはいくらかfluencyがあるはずです。つまり、それを読むときには、引数の意味を知っている必要があります。例:
CopyFolder(文字列パス、ブール再帰);
再帰を最初に置くと、まだコンテキストがないため混乱を招きます。すでにコピー(1)、フォルダー(2)の場合は、再帰的な引数が意味を持ち始めます。
これにより、IntelliSenseのような機能がうまく機能するようになります。ユーザーは、引数を入力するときに学習し、メソッドとその機能の理解を深めます。同様に、オーバーロードは、等しいパーツに対して同じ順序を維持する必要があります。
次に、この点で「等しい」引数があることに気づく場合があり、引数のタイプに応じて順序を変えたくなるかもしれません。いくつかの文字列が連続していて、次にいくつかのブール値が見栄えが良いからです。あるレベルでは、これはスキルではなく芸術になるでしょう。
すべての引数をオブジェクトにラップして、単一の引数で終わるようにする必要があるという文はあまり気にしません。それはあなた自身をだますことです(それはメソッドをそれほど複雑にしません、それはまだこれらすべての引数を持っています、あなたはそれらを単に隠しました)。これは、メソッドからメソッドへのセットを2、3回渡すと便利ですが、リファクタリングは非常に簡単になりますが、設計的には、違いを生み出すふりをしています。何かを表す意味のあるオブジェクトになってしまうのではなく、メソッド宣言のリストと同じように、単なる引数の集まりになります。それはボブおじさんを幸せにすることはありません。
私は通常、必要に応じて最初にそれらを注文します。特定の慣習ではなく、「感情」(ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
と見なすことができます)に従って重要度と使用頻度を組み合わせた尺度ではなく、最初に注文します。
ただし、他の人が指摘しているように、これを問題にする根本的な問題はパラメータの使用が多すぎ(IMHO、3を超えるものは多すぎる)、それが対処すべき本当の問題だと思います。 rebecca murpheyのブログに 興味深い投稿 があります。
引数が1〜3個しかない場合、正しい順序は非常に明白であり、正しいことを「感じる」だけだと思います。
@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
}
お役に立てれば...
カレーが効果を発揮すると思われる方法で注文してください。たとえば、最初に関数のパラメーター。