web-dev-qa-db-ja.com

多くの引数を持つコンストラクターの回避

だから私は異なるクラスのオブジェクトを作成するファクトリーを持っています。可能なクラスはすべて、抽象祖先から派生しています。ファクトリーには構成ファイル(JSON構文)があり、ユーザーの構成に応じて、作成するクラスを決定します。

これを実現するために、ファクトリはJSON解析にboost :: property_treeを使用します。彼はptreeをウォークスルーし、どの具象オブジェクトを作成するかを決定します。

ただし、製品オブジェクトには多くのフィールド(属性)があります。具体的なクラスにもよりますが、オブジェクトには約5〜10個の属性があり、将来的にはさらに増える可能性があります。

そのため、オブジェクトのコンストラクターがどのように見えるかわかりません。私は2つの解決策を考えることができます:

1)製品のコンストラクターはすべての属性をパラメーターとして想定しているため、コンストラクターは最終的に10個以上のパラメーターになります。これは醜く、長くて読めないコード行につながります。ただし、利点は、ファクトリがJSONを解析し、正しいパラメーターでコンストラクターを呼び出すことができることです。製品クラスは、JSON構成のために作成されたことを認識する必要はありません。 JSONや設定が含まれていることを知る必要はありません。

2)製品のコンストラクターは、property_treeオブジェクトという1つの引数のみを予期します。次に、必要な情報を解析できます。構成内の情報が欠落しているか範囲外の場合、各製品クラスは適切に対応できます。工場は、いくつかの製品に必要な引数を知る必要はありません。また、ファクトリーは、構成が誤っている場合の対応方法を知る必要もありません。また、コンストラクターインターフェイスは統一されており、小さいです。ただし、デメリットとして、製品は必要な情報をJSONから抽出する必要があるため、JSONがどのように構成されているかを認識しています。

私は解決策2)を好む傾向があります。ただし、これが良いファクトリパターンであるかどうかはわかりません。 JSON構成で作成されていることを製品に通知するのは、どういうわけか間違っていると感じます。一方、新製品は非常に簡単に導入できます。

それについての意見はありますか?

10
lugge86

私はオプション2を実行しません。それは、ブーストプロパティツリーの解析を使用してオブジェクトの構築を永遠に畳み込んでいるためです。これだけ多くのパラメーターを必要とするクラスに慣れている場合は、そのような多くのパラメーターを必要とするコンストラクターに慣れる必要があります。

コードの可読性が主な関心事である場合は、ビルダーパターンを使用できます。これは基本的に、名前付き引数がないためのc ++/Javaのギャップです。最終的には次のようになります。

MyObject o = MyObject::Builder()
               .setParam1(val1)
               .setParam2(val2)
               .setParam3(val3)
             .build();

そのため、MyObjectには、Builder :: buildで呼び出されるプライベートコンストラクターがあります。いいのは、10個のパラメーターを持つコンストラクターを呼び出さなければならない唯一の場所であることです。ブーストプロパティツリーファクトリはビルダーを使用します。その後、MyObjectを直接または別のソースから構築する場合は、ビルダーを使用します。また、ビルダーでは基本的に、各パラメーターを渡すときに明確に名前を付けることができるため、より読みやすくなっています。これは明らかにボイラープレートを追加するので、乱雑なコンストラクターを呼び出すだけの場合と比較して、既存のパラメーターのいくつかを構造体などにまとめる場合と比較して、その価値があるかどうかを判断する必要があります。テーブルに別のオプションを投げるだけです。

https://en.wikipedia.org/wiki/Builder_pattern#C.2B.2B_Example

10
Nir Friedman

2番目のアプローチは使用しないでください。

これは間違いなく解決策ではなく、ファクトリーがあるアプリの部分ではなく、ビジネスロジックでクラスをインスタンス化するだけです。

どちらか:

  • 同じようなものを表すように見える特定のパラメーターをオブジェクトにグループ化しようとする
  • 現在のクラスをいくつかの小さなクラスに分割します(10個のパラメーターを持つサービスクラスを持つと、クラスがあまりにも多くのことをするように見えます)
  • クラスが実際にはサービスではなく、代わりに値オブジェクトである場合は、そのままにします

作成するオブジェクトが実際にデータの保持を担当するクラスでない限り、コードをリファクタリングして大きなクラスを小さなクラスに分割する必要があります。

5
Andy

オプション2はほぼ正しいです。

改善されたオプション2

JSON構造のオブジェクトを取得してビットを取り出し、ファクトリーコンストラクターを呼び出すのが「フロントフェイス」クラスです。それは工場が作るものを取り、それをクライアントに渡します。

  • このようなJSONが存在することさえ、ファクトリーはまったく考えていません。
  • クライアントは、ファクトリが必要とする特定のビットを知る必要はありません。

基本的に「フロントエンド」は the 2 Bobs: "redactedの顧客に対応するため、エンジニアは必要ありません。人のスキル!」貧しいトム。彼が「私はクライアントを建設から切り離しました。この結果は非常にまとまりのある工場です」と言っただけなら;彼は仕事を続けたかもしれない。

引数が多すぎますか?

クライアント向けではありません-フロントエンド通信。

フロントエンド-工場? 10個のパラメーターでない場合は、アンパックを延期することをお勧めします。元のJSONでない場合は、DTOを使用します。これは、JSONをファクトリーに渡すよりも優れていますか?私が言うのと同じ違い。

個別のパラメーターを渡すことを強く検討します。クリーンでまとまりのある工場という目標に固執する。 @ DavidPacker answer。 の心配を避けてください。

「引数が多すぎます」の軽減

  • ファクトリまたはクラスコンストラクター

    • 特定のクラス/オブジェクト構築の引数のみを取ります。
    • デフォルトのパラメータ
    • オプションのパラメーター
    • 名前付き引数
  • フロントエンド引数のグループ化

    • 上記のコンストラクターシグネチャによって導かれた引数値を調べ、評価し、検証し、設定します。
0
radarbob