エンティティの代わりにDTOを使用するとどうなりますか?


18

私はRCPアプリケーションに取り組んでいます。このアプリケーションは初めてです。

Spring Beanは、エンティティを保存/取得するビジネスロジックを記述するために使用されます。

ただし、エンティティを直接クライアントに送信する代わりに、DTOに変換してクライアントにデータを入力しています。保存中に、再びDTOをエンティティに変換して保存します。

これらの変換の利点は何ですか?誰か説明できますか?


What's the benefit of these conversions?消費者に提供されるデータモデル(表現)から永続性データモデルを分離します。分離の利点はSEで広く議論されていますが、DTOの下の目的は、クライアントがサーバーへの呼び出しを保存するために必要と思われる情報を1つの応答に集めることです。通信クライアント/サーバーをよりスムーズにするもの。
ライヴ


あなたの例は素晴らしいです。あなたがクライアント(ビュー...)である場合、変更するのは苦痛ですが、最大の問題は、システムにサードパーティの統合がすでにある場合、変更することは不可能です(契約、料金...)。システムにサードパーティの統合がある場合は、DTOを使用してください。
ルーカスゴンサル

回答:


44

開発者が「これを行うことのポイントは何ですか?」そのために、いくつかの例を示します。


すべての例は、この単純なデータモデルに基づいています。

Personエンティティは、5つのプロパティがあります。Id, FirstName, LastName, Age, CityId

また、アプリケーションがこのデータをさまざまな方法(レポート、フォーム、ポップアップなど)で使用すると想定できます。

アプリケーション全体が既に存在します。私が言及するすべては、既存のコードベースへの変更です。これは覚えておくことが重要です。


例1-基礎となるデータ構造の変更-DTOなし

要件が変更されました。その人の年齢は、政府のデータベースから動的に取得する必要があります(名と姓に基づいて想定しましょう)。

Age値をローカルに保存する必要がなくなったため、Personエンティティから値を削除する必要があります。ここで重要なのは、エンティティがデータベースのデータを表しそれ以上のものではないことを認識することです。データベースにない場合は、エンティティにありません。
政府のWebサービスから年齢を取得すると、別のオブジェクト(またはint)に保存されます。

ただし、フロントエンドにはまだ年齢が表示されます。このPerson.Ageプロパティを使用するようにすべてのビューが設定されましたが、現在は存在していません。問題はそれ自身を示します:人のを参照するすべてのビューをAge修正する必要があります


例2-基礎となるデータ構造の変更-DTOを使用

古いシステムではPersonDTO、同じ5つのプロパティを持つエンティティもありますId, FirstName, LastName, Age, CityId。aを取得した後Person、サービス層はそれをaに変換してからPersonDTO返します。

しかし、現在、要件は変更されています。その人の年齢は、政府のデータベースから動的に取得する必要があります(名と姓に基づいて想定しましょう)。

Age値をローカルに保存する必要がなくなったため、Personエンティティから値を削除する必要があります。ここで重要なのは、エンティティがデータベースのデータを表しそれ以上のものではないことを認識することです。データベースにない場合は、エンティティにありません。

ただし、仲介者PersonDTOがいるため、このクラスがAgeプロパティを保持できることを確認することが重要です。サービス層はを取得しPerson、に変換してPersonDTOから、政府のWebサービスからその人の年齢を取得し、その値をに格納してPersonDTO.Age、そのオブジェクトを渡します。

ここで重要な部分は、サービス層を使用する誰もが古いシステムと新しいシステムの違いを見ないということです。これにはフロントエンドが含まれます。古いシステムでは、完全なPersonDTOオブジェクトを受け取りました。そして、新しいシステムでは、まだ完全なPersonDTOオブジェクトを受け取ります。ビューを更新する必要はありません

これは、懸念の分離というフレーズを使用する場合の意味です。2つの異なる懸念(データベースへのデータの保存、フロントエンドへのデータの提示)があり、それぞれ異なるデータタイプが必要です。これらの2つのデータ型にたまたま同じデータが含まれていたとしても、将来的に変更される可能性があります。
与えられた例では、Age2つのデータ型との間の差である:Person(データベース・エンティティ)必要はないAgeが、PersonDTO(フロントエンド・データ・タイプ)は、それを必要はありません。
懸念事項を最初から分離する(=個別のデータ型を作成する)ことにより、コードベースはデータモデルに加えられた変更に対してより回復力があります。

データベースに新しい列が追加されたときにDTOオブジェクトがあると、エンティティとDTOの両方にプロパティを追加して、2つの作業を行う必要があることを主張するかもしれません。それは技術的に正しいです。1つではなく2つのクラスを維持するには、少し余分な労力が必要です。

ただし、必要な労力を比較する必要があります。1つ以上の新しい列が追加されると、いくつかのプロパティのコピー/貼り付けにそれほど時間がかかりません。データモデルが構造的に変更され、フロントエンドを変更する必要がある場合、おそらく実行時(コンパイル時ではなく)バグを引き起こすような方法で、かなり多くの労力がかかり、開発者はバグを探しに行く必要があります。


もっと例を挙げることができますが、原則は常に同じです。

要約する

  • 別々の責任(懸念)は、互いに別々に働く必要があります。データクラスなどのリソースを共有しないでください(例Person
  • エンティティとそのDTOが同じプロパティを持っているからといって、それらを同じエンティティにマージする必要があるという意味ではありません。角を切らないでください。
    • より露骨な例として、データベースに国、歌、人が含まれているとします。これらのエンティティにはすべてがありNameます。しかし、それらがすべてNameプロパティを持っているからといって、共有EntityWithNameベースクラスから継承させる必要があるわけではありません。異なるNameプロパティには意味のある関係はありません。
    • プロパティの1つが変更された場合(たとえば、曲のName名前が変更されTitleたり、人がFirstNameandを取得したLastName場合)、そもそも必要のない継承取り消すために、より多くの労力を費やす必要があります
    • それほど明白ではありませんが、エンティティを持っているときにDTOを必要としないというあなたの主張は同じです。あなたはを見ていますが、将来の変更に備えていません。IFエンティティとDTOはまったく同じであり、IFあなたはデータモデルに変更があったことがないことを保証することができます。DTOを省略できることは正しいです。ただし、データモデルが変更されないことを保証できないということです。
  • 良い習慣がすぐに報われるとは限りません。古いアプリケーションを再検討する必要がある場合、将来的には成果を上げる可能性があります。
  • 既存のコードベースの主なキラーは、コード品質が低下し、コードベースを維持するのがますます難しくなることです。
  • コードベースをできるだけ長く維持できるようにするために、懸念事項と到達点の分離を実装するなどのグッドプラクティスは、悪いメンテナンスの滑りやすい勾配を回避することを目的としています。

懸念事項の分離を検討するための経験則として、次のように考えてください。

すべての懸念事項(UI、データベース、ロジック)が異なる場所にいる別の人によって処理されると仮定します。彼らは電子メールでのみ通信できます。

十分に分離されたコードベースでは、特定の懸念事項への変更は1人で処理する必要があります。

  • ユーザーインターフェイスの変更には、UI開発のみが含まれます。
  • データ保存方法の変更には、データベース開発者のみが関係します。
  • ビジネスロジックの変更には、ビジネス開発者のみが関与します。

これらの開発者全員が同じPersonエンティティを使用しており、エンティティに小さな変更が加えられた場合、全員がプロセスに関与する必要があります。

しかし、レイヤーごとに個別のデータクラスを使用することにより、その問題はそれほど一般的ではありません。

  • データベース開発者が有効なPersonDTOオブジェクトを返すことができる限り、ビジネスおよびUI開発者は、データの保存/取得方法を変更したことを気にしません。
  • ビジネス開発者がデータベースにデータを保存し、必要なデータをフロントエンドに提供する限り、データベースとUI開発者は、ビジネスルールを作り直すことにしたかどうかは気にしません。
  • UIが `PersonViewModelに基づいて設計できる限り、UI devは必要に応じてUIを構築できます。データベースおよびビジネス開発者は、それらに影響を与えないため、それがどのように行われるかを気にしません。

ここでのキーフレーズはそれが彼らに影響しないからです。懸念事項を適切に分離することで、他の関係者への影響を最小限に抑えます(したがって、関与する必要があります)。

もちろん、いくつかの大きな変更は、たとえばまったく新しいエンティティがデータベースに追加された場合など、複数の人を含めることを避けることができません。ただし、アプリケーションの存続期間中に行う必要がある小さな変更の量を過小評価しないでください。大きな変更は、少数の数値です。


包括的な答え、ありがとう。質問があります。あなたが答えれば感謝します:1-私が間違っているなら、私を修正してください。ビジネスオブジェクトまたはビューオブジェクトは、プレゼンテーション層ビジネス層の間でデータを転送するためのものであり、エンティティオブジェクトは、ビジネス層データアクセス層の間でデータを転送するためのものです。また、DTOはダムBOとして使用できます。2-2つのビューに会社の異なる情報が必要である場合、2つの異なるcompanyDTOが必要だと仮定します
アラシュ

1
@Arash(1)「DTO」は、2つのレイヤー間での交換に使用されるデータクラスのキャッチオール定義です。ビジネスオブジェクトとビューオブジェクトはどちらもDTOです。(2)それは非常に多くのことに依存しています。必要なフィールドのコレクションごとに新しいdtoを作成するのは面倒な作業です。会社の完全なDTO(妥当な場合)を返すだけで本質的に問題はありません。次に、関心のあるフィールドをビューに選択させます。問題の適切な分離の実装と、過剰なエンジニアリングと無意味な繰り返しの回避のバランスを見つけることです。
平らな

今ではそれは理にかなっています。どうもありがとう。平ら。
アラシュ

もう一つ質問。あなたは「ビジネスオブジェクトビューオブジェクト」言いました。私は両方が等しいと思った。検索すると、ビジネスオブジェクトにビューオブジェクトと比較する一般的な意味があることに気付きました。しかし、ビジネスオブジェクトユースケースから派生し、エンティティオブジェクトデータモデルから派生する必要があります。したがって、それらは異なります。少し説明してもらえますか?
アラシュ

@Arash:「ビジネスオブジェクト」と「ビューオブジェクト」と呼ぶものの違いはコンテキストです。私たち人間にとって、その区別は物事を適切に理解するために重要です。しかし、コンパイラー(および拡張機能によって言語自体)は、それらの技術的な違いを認識しません。私はそれらが同じだと言うとき、私は技術的な観点からそれを意味します。どちらも、データを保持して渡すためのプロパティを持つクラスです。その点で、それらの間に違いはありません。
平らな
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.