次のことを行う必要があるプロジェクトがあるとします。
一部の値オブジェクトには、メソッドに必要なフィールドよりも多くのフィールドがある場合があるので、2番目の箇条書きのメソッドのパラメーターのベストプラクティスをブレインストーミングしようとしています。
それぞれが作業の一部を行う多くのクラスを用意することで、2番目の箇条書きを達成したいとします。たとえば、あるクラスが1つの値オブジェクトの7つのフィールドと別の値オブジェクトの8つのフィールドを必要とし、両方の値オブジェクトにそれぞれ30以上のフィールドがあるとします。これを行う3つの方法を考えることができます。
クラスに、パラメーターとして必要な2つの値オブジェクトを受け入れさせます。次に、クラスは15のゲッターを呼び出し、フィールドを使用して何かを行います。残りのクラスでも、同じ方法を使用して、必要な値オブジェクトを受け取ります。
必要な15個の値のみを格納する新しい値オブジェクトをコード化します。アプリケーションのどこかで、これらの2つの値オブジェクトから新しい値オブジェクトへのマッピング/変換を行う必要があります。私のクラスは15のゲッターを呼び出し、フィールドで何かを行います。残りのクラスでも同じ方法を使用します
2番目の箇条書き全体に必要なすべてのデータを格納する巨大な値オブジェクトをコード化します。基本的に、すべての値オブジェクトを取得し、必要なすべてのデータをこの巨大な値オブジェクトに変換します。次に、私のクラスはこの巨大な値オブジェクトを受け取ります。私のクラスは15のゲッターを呼び出し、フィールドで何かを行います。ロジックの一部を実行する各クラスは、この巨大な値オブジェクトを受け取ります
どちらが最善のアプローチですか?
最も簡単なアプローチのようです。しかし、必要以上の情報を要求するクラスを持っているのは奇妙に感じられます。クラスを見る人は、15フィールドだけを使用するのに60フィールドを要求する理由を知りたいと思うかもしれません。
には多くの異なるマッピングがあるため、はるかに複雑なようですが、個々のクラスは必要なものだけを要求することになります。
通常、最善のアプローチは1つだけではないため、最善のアプローチを探すことは、ソフトウェアエンジニアリングにおいて常に厄介なことです。それぞれのアプローチには、状況によってそれを改善または悪化させるトレードオフがあります。
最適化する対象のリストの上位にあるべき1つのことは、可読性と保守性です。これにより、以前にコードを見たことがない、またはしばらく見たことがない人でも、コードの機能を簡単に理解できます。
読みやすさの1つの側面は、首尾一貫した概念を表すクラスを持つことです。値オブジェクトは、コンテナーで一緒にスローされる一連のプロパティではありません。値オブジェクトは、エンティティと同様に、一貫した概念を表す必要があります。たとえば、通りの住所には通りの名前、都市、郵便番号などのいくつかのプロパティがありますが、次の理由から、通りの住所と家の色のプロパティで構成される値オブジェクトを作成しないでください。一部の機能に便利です。ほとんどの場合、そのプロパティのコレクションは複数の概念を表し、複数の値オブジェクトに分割する必要があります。
これにより、お客様の質問に対する回答が得られます。
オプション1の現在の値オブジェクトがそれぞれ1つの一貫した概念を表す場合、オプション1が最も確実に選択できるオプションです。すべての関数が値オブジェクトのすべてのプロパティを必要とするわけではないことは非常に自然です(特に、それが多くのプロパティを持つかなり大きい場合)、それは問題ではありません。よく理解されている概念の一部だけが使用されているのを見ることは、通常、ランダムなプロパティのバッグに対する操作を見るよりも理解しやすいです。
現在の値オブジェクトが単一の一貫した概念を表していない場合は、オプション4を提供します。それぞれが単一の一貫した概念を表す新しい値オブジェクトを作成し、それらに基づいて操作を行います。
1)クラスに、パラメーターとして必要な2つの値オブジェクトを受け入れさせます。次に、クラスは15のゲッターを呼び出し、フィールドを使用して何かを行います。残りのクラスでも、同じ方法を使用して、必要な値オブジェクトを受け取ります。
これは貧血領域アプローチです。 DB、テーブル、フィールドを決して変更しない場合、またはそのような変更が多くの場所で多くのことを壊してもかまわない場合は、正常に機能します。これは、アプリケーションがDBの詳細に精通していることを意味します。
2)必要な15個の値のみを格納する新しい値オブジェクトをコード化します。アプリケーションのどこかで、これらの2つの値オブジェクトから新しい値オブジェクトへのマッピング/変換を行う必要があります。私のクラスは15のゲッターを呼び出し、フィールドで何かを行います。残りのクラスでも同じ方法を使用します
パラメーターオブジェクトの導入 リファクタリングの適用はこれで終わりです。いくつかのメソッドのすべてのパラメーターを1つのパラメーターオブジェクトに押し込むだけではありません。メソッドのパラメーターを分割してグループ化すると、概念的に一貫したグループを保持する引数の数が少なくなります。これらの小さなデータ転送オブジェクトはそれぞれ、メソッドのニーズの一部に焦点を当てることができます。それらは再利用可能かもしれません。
たとえば、これをリファクタリングしないでください:
void draw(int x, int y, int r, int g, int b)
これに:
void draw(DrawArgs drawArgs)
これにリファクタリングします:
void draw(Point point, Color color)
DBにデータのみがあり、ポイントと色が何であるかわからない場合でも、これを行ってください。
3)2番目の箇条書き全体に必要なすべてのデータを格納する巨大な値オブジェクトをコード化します。基本的に、すべての値オブジェクトを取得し、必要なすべてのデータをこの巨大な値オブジェクトに変換します。次に、私のクラスはこの巨大な値オブジェクトを受け取ります。私のクラスは15のゲッターを呼び出し、フィールドで何かを行います。ロジックの一部を実行する各クラスは、この巨大な値オブジェクトを受け取ります
これは 神オブジェクト と呼ばれます。それは、組織化をあきらめて、すべてを1か所に捨てるときに起こります。混乱をどこかに隠しているだけです。
20の異なるクラスに属する値オブジェクトを入力として受け取る非常に複雑な処理があります。 それらがアプリケーションドメインの適切に定義された一貫したオブジェクトであると仮定しましょう。
デザインは、ドメインオブジェクトの複雑な処理を、管理しやすい小さなクラスにカプセル化された小さなタスクに細分します。
ここではオプション1が最も適切な選択のようです:明確に定義された一貫したドメインオブジェクトを入力として受け取り、それらの一部のみが必要です。これには大きな利点があります。
他のすべての選択肢はあまり最適ではありません。
うーん...だから、複数の値オブジェクト(おそらく投稿によると20以上)があり、それらは互いに複数の関係を持ち、オーケストレーションが必要です。
これは、エンドツーエンドプロセスを構成する2つのエンタープライズ統合パターン(EIP)のように聞こえます。あなたのプロセスは次の操作を実行する必要があるようです。
あなたが達成したいことのための最良のツールは、あなたのVOのオーケストレーション、組み立て、そして充実を備えた「ビルダーパターン」だと思います。私はあなたがしたいことのためにApache Camelを使います。