web-dev-qa-db-ja.com

関数の引数の数を最小限にするための手法

クリーンコードでは、「関数の引数の理想的な数はゼロ」と書かれています。理由が説明され、理にかなっています。私が求めているのは、この問題を解決するために4つ以上の引数を持つメソッドをリファクタリングする手法です。

1つの方法は、引数を新しいクラスに抽出することですが、それは確かにクラスの爆発的な増加につながるでしょうか?そして、それらのクラスは、いくつかの命名規則に違反する名前で終わる可能性があります(「Data」または「Info」などで終わる)?

別の手法は、複数の関数で使用される変数をプライベートメンバー変数にして、それらを渡さないようにすることですが、これにより変数のスコープが拡張され、実際にはそれを必要としない関数に開かれる可能性があります。

関数の引数を最小化する方法を探しているだけで、そうするのが良い理由を受け入れました。

13
Neil Barnwell

覚えておくべき最も重要なことは、これらはルールではなくガイドラインであることです。

メソッドが単にmustが引数をとる場合があります。たとえば、数値の+メソッドについて考えます。または、コレクションのaddメソッド。

実際、2つの数値を加算することの意味はコンテキストに依存すると主張する人もいます。 ℤ3 + 3 == 6にありますが、ℤ| 5 3 + 3 == 2なので、実際には、加算演算子は、1つの引数を取る数値のメソッドではなく、2引数を取るコンテキストオブジェクトのメソッドである必要があります。

同様に、2つのオブジェクトを比較するメソッドは、一方のオブジェクトが他方を引数として取るメソッドであるか、または2つのオブジェクトを引数として受け取るコンテキストのメソッドでなければならないので、引数が1つ未満です。

つまり、メソッドの引数の数を減らすためにできることがいくつかあります。

  • メソッド自体を小さくする:メソッドにそれほど多くの引数が必要な場合、多すぎますか?
  • 不足している抽象化:引数が密接に相関している場合、おそらくそれらは一緒に属していて、不足している抽象化がありますか? (標準的な教科書の例:2つの座標の代わりにPointオブジェクトを渡すか、ユーザー名と電子メールを渡す代わりにIdCardオブジェクトを渡します。)
  • Object state:複数のメソッドで引数が必要な場合は、オブジェクトの状態の一部である必要があります。一部のメソッドのみで必要とされ、他のメソッドでは必要とされない場合、オブジェクトが多すぎるため、実際には2つのオブジェクトである必要があります。

1つの方法は、引数を新しいクラスに抽出することですが、それは確かにクラスの爆発的な増加につながるでしょうか?

ドメインモデルにさまざまな種類のものが含まれている場合、コードにはさまざまな種類のオブジェクトが含まれます。それには何も問題はありません。

そして、それらのクラスは、いくつかの命名規則に違反する名前で終わる可能性があります(「Data」または「Info」で終わるなど)?

適切な名前が見つからない場合は、グループ化した引数が多すぎるか、または少なすぎる可能性があります。したがって、クラスのフラグメントのみを持っているか、複数のクラスを持っています。

別の手法は、複数の関数で使用される変数をプライベートメンバー変数にして、それらを渡さないようにすることですが、これにより変数のスコープが拡張され、実際にはそれを必要としない関数に開かれる場合があります。

同じ引数を操作するメソッドのグループと、そうでないメソッドのグループがある場合、それらは異なるクラスに属している可能性があります。

「多分」という言葉をどれだけ頻繁に使用したかに注意してください。それがルールではなくガイドラインである理由です。たぶん、4つのパラメーターを使用するメソッドは完全にうまくいきます

16
Jörg W Mittag

オブジェクトは暗黙的な引数であるため、引数がゼロであっても副作用はありません。たとえば、ゼロアリティメソッド Scalaの不変リスト がいくつあるか見てみましょう。

私が「レンズの焦点合わせ」と呼ぶ便利なテクニックの1つ。カメラレンズの焦点を合わせるときに、遠くに置くと本当の焦点を確認しやすくなり、正しい位置に戻します。ソフトウェアリファクタリングについても同様です。

特に、分散バージョン管理を使用している場合は、ソフトウェアの変更を簡単に試して、見た目が良いかどうかを確認し、そうでない場合は取り消すことができますが、なぜか人々はそうしたがらないことがよくあります。

あなたの現在の質問の文脈では、それは最初にいくつかの分割された関数でゼロまたは1つの引数バージョンを書くことを意味します、そしてそれからどの関数が読みやすさのために組み合わせる必要があるかを比較的簡単に見ることができます。

著者はまた、テスト駆動型開発の大きな擁護者であることに注意してください。これは、些細なテストケースから始めるため、最初は低アリティ関数を生成する傾向があります。

6
Karl Bielefeldt

単純に(そして単純に-またはblindlyと言うべきか)、関数への引数の数を減らすことを目的とするアプローチは、おそらく間違っていません。多数の引数を持つ関数に問題はありません。ロジックで必要とされる場合、それらも必要です...長いパラメーターリストは、読みやすくするために適切にフォーマットおよびコメント化されている限り、まったく心配ありません。

引数のすべてまたはサブセットが1つの一意の論理エンティティに属し、プログラム全体でグループで渡されることが多い場合、maybeをそれらをいくつかのコンテナーにグループ化することは理にかなっています-通常は構造体またはその他オブジェクト。典型的な例は、ある種のmessageまたはeventデータ型です。

このアプローチは簡単にやり過ぎることができます。このようなトランスポートコンテナーとの間でデータをパックおよびアンパックすると、読みやすさが向上するよりもオーバーヘッドが大きくなることがわかった場合は、おそらく行き過ぎです。

OTOH、大きなパラメーターリストは、プログラムが適切に構造化されていない可能性があることを示している可能性があります。このような多数のパラメーターを必要とする関数あまりに多くのことを実行しようとしているであり、いくつかの小さなパラメーターに分割する必要があります機能。パラメータの数について心配するよりも、ここから始めたいと思います。

0
tofro

魔法の方法はありません。適切なアーキテクチャを発見するには、問題のある領域をマスターする必要があります。それがリファクタリングの唯一の方法です。問題のあるドメインを習得します。 4つ以上のパラメータは、現在のアーキテクチャに欠陥があり、間違っていることを確信しています。

唯一の例外は、コンパイラ(メタプログラム)とシミュレーションです。制限は理論的には8ですが、おそらく5だけです。

0
theDoctor