web-dev-qa-db-ja.com

独自のタイプのArrayListを持つDTOクラス-これは良い設計と見なされますか?

以下のようなDTOクラスに出会いました。

class PersonDTO {
   private String firstName;
   private String middleName;
   private String lastName;
   private String dob;

   // some 50 fields more
   private List<PersonDTO> persons;

   //getters and setter
}

質問1:非常に多くのプロパティを持つこのような巨大なDTOクラスを持つことは良い習慣ですか?

質問2:独自のタイプのArrayListを持つDTOクラスを作成することは良い習慣ですか?それは循環参照を引き起こしませんか?

更新:

私はヘルスケア分野の製品で働いています。ユースケースは、システム内のすべてのユーザーのレポートを生成することです。ユーザーのリストに加えて、レポートには要約情報も表示する必要があります。 UIはJSON応答を想定しているため、データをシリアル化する必要があります。

以下は私が取り掛かっていた実際のDTOです。

メソッドはDAOクラスで作成され、UserDTOオブジェクトを返します。返されるこのUserDTOオブジェクトは、すべてのユーザーのリストと、合計医師、合計看護師などのいくつかの要約情報で構成されています。

class UserDTO{
    private String userID; //This is unique

    private String firstName;
    private String middleName;
    private String lastName;
    private String dob;

    private String userType; // value can be DT(for doctor), ST(for nurse), 

    private int totalDoctorCount; //Holds the total number of UserDTOs with userType value set to DT in the ArrayList of users.

    private int totalNurseCount; //Holds the total number of UserDTOs with userType value set to ST in the ArrayList of users.


    // there are some 40 more properties.

    private List<UserDTO> users;

        //In this class there are also properties like below... 

        private String primaryAddrStreetName;
        private String primaryAddrCity;
        private String primaryAddrState;
        private String primaryAddrCountry;
        private String primaryAddrZipcode;

        private String billingAddrStreetName;
        private String billingAddrCity;
        private String billingAddrState;
        private String billingAddrCountry;
        private String billingAddrZipcode;

        private String shippingAddrStreetName;
        private String shippingAddrCity;
        private String shippingAddrState;
        private String shippingAddrCountry;
        private String shippingAddrZipcode;
}

質問3:このDTO設計はそのユースケースに適していますか?そうでない場合、あなたは何を提案しますか?

質問4:ユーザーが複数のアドレスを持っています。しかし、アドレスの詳細はそれ自体のクラス(UserAddressDTOのよ​​うなもの)にあるべきではなく、UserDTOにUserAddressDTOの配列/ ArrayListを追加する必要がありますか?

質問5:また、このような種類のDTOがJVMメモリにどのように影響するかについても洞察を与えてください。レポートは何千ものレコードをフェッチします。

6
madan

質問1:巨大なDTO

DTOの目標 は、プロセスまたはレイヤー間でデータを転送して、メソッド呼び出しの数を減らすことです。

したがって、そのような構造のフィールドの膨大なリストがあることは衝撃的ではありません。別の方法としては、たとえば ResultSet (または--a(non-jaaコンテキストでは dataset )など)のような、より複雑な構造でDTOを実装します。異なるエンティティを1つのオブジェクトにグループ化します。その場合、不便なのは、そのようなオブジェクトの構築とその要素へのアクセスに時間がかかることです。これは、フラットな(そして醜いが効率的な)構造の場合です。

参考までに、 ここ DTOのいくつかの利点と欠点を見つけることができます。

質問2(編集後に更新)**

PersonDTOPersonDTOのリストがあることは、DTOが再帰的な構造(ツリーなど)を持っていることを意味します。したがって、これは1つのPersonのフラットデータだけでなく、実際には1つのPersonと関連するPersonsのグループです。データ構造は再帰的です。

これは循環参照を意味するものではありませんが、あなたの言う通り、追加の注意が必要です。それはすべて元のデータ構造に依存します:

  1. 元のオブジェクトが階層を形成している場合(たとえば、マネージャーとその従業員、それらの一部は自分自身にマネージャーがおり、独自の従業員がいる)、DTOを作成する問題はありません。それが非循環グラフの別の形式である場合も同じです。
  2. 元のオブジェクトがサイクルの可能性があるグラフを形成している場合(たとえば、人とその友達)、DTOを構築するときにいつまでも循環するリスクがあります。サイクル検出を使用して、同じオブジェクトが何度も転送されるのを防ぐことができます。ただし、これを行うと、転送で一部の関係が失われます。この場合、このDTOは不適切な設計になります。

また、同じ人物がDTOの異なるリストに複数回出現する可能性があることにも注意してください(例:2つの部門で働いている非常勤の従業員)。残念ながら、データ転送中に、オブジェクトが逆シリアル化されてネット経由で転送され、その後再びシリアル化されると、オブジェクトのID(Javaに同じ参照がある))が失われる可能性があります。同じデータをレプリケートする2つの異なるオブジェクトが作成されます。したがって、受信側では、さらに注意する必要があります。そのようなオブジェクトのIDを検出するか、想定するかを決定する必要があります。すべての人は常に異なるでしょう。

結論:この構造は問題ないかもしれませんが、元のドメインオブジェクトに関するいくつかの情報を確認する必要があります。

代替:より安全なDTO構造は、各個人にIDを与え、DTOをIDを持つ個人のコレクションとして編成することです。次に、PersonDTOのリストをIDのリストで置き換えることができます。これは、すべてのタイプの人物グラフで機能し、アイデンティティ検出を必要としないため、はるかに柔軟です。

質問3と最後の編集

このDTO構造の目的が無関係なユーザーのリストを提供することだけである場合は、次の構造にする必要があります。

class UserDTO {             // Only properties of a single user
    private String userID; 
    private String firstName;
    ...
    private String userType;  
};
class UserListDTO {         // Only properties of the list as a whole
    private int totalDoctorCount; 
    ...
    private List<UserDTO> users;
};

ご覧のとおり、適切なDTO設計は、多くの場合、DTOクラスの乗算に関連しています。 この記事はこちら で公開されている欠点で確認できるように、これはよく知られているトピックです。

一意のDTOを拡張して2つのレイヤーを1つのクラスに結合することは、 単一の責任の原則 に準拠しないショートカットです。また、あいまいです。最上位のユーザーをグループに追加する必要があるかどうか。それから彼は統計に数えられますか?リストのユーザーは常に空のリストを持つ必要がありますか?彼らは彼ら自身の統計を提供しませんか?リストの1人のユーザーが彼のリストに予期しないユーザーを連れてきた場合はどうなりますか?これらすべての質問と追加の処理、1つの追加クラスを回避するために...

この場合、それは悪い設計です。

6
Christophe

ウィキペディア

データ転送オブジェクト(DTO)は、プロセス間でデータを運ぶオブジェクトです。その使用の動機は、プロセス間の通信が通常、リモートインターフェース(Webサービスなど)を使用して行われることです。この場合、各呼び出しは高価な操作です。各呼び出しのコストの大部分はクライアントとサーバー間の往復時間に関連しているため、呼び出しの数を減らす1つの方法は、転送されたであろうデータを集約するオブジェクト(DTO)を使用することですいくつかの呼び出しによって、しかしそれは1つの呼び出しによってのみ提供されます

上記の定義によれば、DTOがプロセス間の呼び出しの数を減らすように対処されている場合、DTOのサイズについては議論できますが、その妥当性については議論できません。一方、DTOがコミュニケーション戦略に応答しない場合、おそらく回答はです。設計を確認してください。 DTOを利用しようとする人は誰でも、そのような怪物からデータを探索、分析、抽出するのに苦労します。

2番目の質問に関しては、何らかの理由で同じDTOがリストのどこかで参照されているか、DTOの内部リストのいずれかによって参照されている場合、循環参照が発生する可能性があります。等々。


編集後の更新

@Christopheはすでに私たち全員が(多かれ少なかれ)考えていることを伝えています。 UserDTOがレポートに必要なすべてのデータを保持している場合、提供した責任が多すぎます。

次の2つのオプションを検討してください。

  • 他のDTOと独自のローカル属性で構成されるWebリソースReportDTOのモデリング。

  • サーバーへの呼び出しを増やします。 DTOの目的はこれとは逆であることはわかっていますが、怒ってはいけません。呼び出しを50に減らして1にするのはすばらしいことですが、1つのDTOを実装するリスクがあるので(DTO 1つですべてを持ち込み、暗闇の中でそれらをバインドします)。呼び出し回数を50から5に減らしても、大幅な改善です。

1
Laiv

質問1:非常に多くのプロパティを持つこのような巨大なDTOクラスを持つことは良い習慣ですか?

他の人が述べたように、消費者がそれを必要とする場合、DTOは確かにそれほど大きくなる可能性があります。 DTOは非常に狭い目的を果たしているため、DTOを使用しても実際に「実用性」の変化がないため、このような大きなDTOが良い方法であるかどうかについてコメントすることは困難です。

質問2:独自のタイプのArrayListを持つDTOクラスを作成することは良い習慣ですか?それは循環参照を引き起こしませんか?

Modellingに関して、Personは他の複数のPersonsで構成されていません。 Personは、複数のsiblingstypePersonを持つことができます。 personsと呼ばれるメンバーであるポイントは、オブジェクトとの関係に関する関連情報を伝えません。一方、siblingsという名前のメンバーが、これらのPersonインスタンス間のおなじみの関係を記述していることは明らかです。

1
MetaFight

50個のプロパティは少し過剰に見えます。あなたはそれらを可能な限りトリムしてみて、保つべきです。必要なものだけを含めてください。私は10-15のプロパティであるものを見てきましたが。

ArrayListに関しては、問題なく作成できます。循環参照は、何らかの理由で、作業を行っている実際のアイテムを参照またはそのような変なものとして保存した場合にのみ発生します。

0
Rhys Johns