プレーンな古いCLRオブジェクトとデータ転送オブジェクト


405

POCO = Plain Old CLR(またはそれ以上:クラス)オブジェクト

DTO =データ転送オブジェクト

この投稿には違いがありますが、率直に言って、私が読んだほとんどのブログでは、DTOの定義方法についてPOCOについて説明しています。DTOは、アプリケーションのレイヤー間でデータを移動するために使用される単純なデータコンテナーです。

POCOとDTOは同じものですか?


5
「POCO = Plain Old CLR(またはそれ以上:Class)オブジェクト」。したがって、VB.NETにおけるこの性質のオブジェクトもPOVOではなくPOCOになります。
J. Polfer 2013年

回答:


568

POCOはOOPのルールに従います。状態動作が必要です(必須ではありません)。POCOは、Martin Fowler [ 逸話はこちら ] によって造られたPOJOから来てます。彼はPOJOという用語を、フレームワークの重いEJB実装を拒否することをよりセクシーにする方法として使用しました。POCOは.Netの同じコンテキストで使用する必要があります。フレームワークにオブジェクトの設計を指示させないでください。

DTOの唯一の目的は状態を転送することであり、動作はありません。このパターンの使用例については、 Martin FowlerによるDTO説明を参照してください。

違いは次のとおりです。POCOはプログラミング(古き良きオブジェクト指向プログラミング)へのアプローチを説明します。DTOは、オブジェクトを使用して「データを転送」するために使用されるパターンです。

POCOをDTOのよ​​うに扱うことはできますが、そうする場合は貧血ドメインモデルを作成するリスクがあります。さらに、DTOはビジネスドメインの真の構造を表すのではなく、データを転送するように設計する必要があるため、構造に不一致があります。この結果、DTOは実際のドメインよりもフラットになる傾向があります。

合理的な複雑さのドメインでは、ほとんどの場合、個別のドメインPOCOを作成し、それらをDTOに変換する方がベターです。DDD(ドメイン主導の設計)は、汚職防止レイヤーここに別のリンクがあります、本を購入することをお勧めします)を定義します。これは、分離を明確にする優れた構造です。


私はここでマーティンファウラーをたくさん参照しましたが、彼はPOJOという用語を作り、DTOの最も信頼できるリファレンスであるPoEAAという本を書きました。
マイケルメドウズ

DTOに動作が必要かどうかはわかりません。MartinFowlerの図で判断すると、DTOには動作がある可能性があります。
Beatles1692 2009年

39
@ Beatles1692、描かれているメソッドはシリアル化コードです。おそらく、「行動なし」と言うには広すぎる文です。「ビジネスロジックなし」はどうですか。シリアライゼーションコード、およびハッシュコード、等価性、tostringなどの低レベルのオブジェクトのものは受け入れられるべきです。
マイケルメドウズ

1
@PositiveGuyモデルはDTOとは異なる目的を果たします。DTOは、あるドメインから別のドメインにデータを転送するためのものです(同じランタイム内にあるかどうかは関係ありません)。モデルは、画面、サービス、データソースなどのドメインの側面を「表現」します。モデルには状態と動作が含まれ、それらはモデル化するものの代表です。
Michael Meadows

2
特にアプリがほとんどCRUDである場合、貧血ドメインモデルは必ずしも悪いわけではないことに注意してください。マーティンファウラーよりもシンプルさを優先します。
Mariusz Jamro

50

ブログの記事で自分の立場をすでに述べたので、貢献することはおそらく冗長ですが、その記事の最後の段落では、次のように要約しています。

したがって、結論として、POCOを愛することを学び、DCOと同じものであるという誤った情報を広めないようにしてください。DTOは、アプリケーションのレイヤー間でデータを移動するために使用される単純なデータコンテナーです。POCOは完全なビジネスオブジェクトであり、永続性を無視する(getまたはsaveメソッドを使用しない)ことが1つの要件です。最後に、Jimmy Nilssonの本をまだチェックアウトしていない場合は、地元の大学の本から取り出してください。C#の例があり、読みやすくなっています。

ところで、パトリック私はPOCOをライフスタイルの記事として読みました、そして私は完全に同意します、それは素晴らしい記事です。それは実際に私が推薦したジミー・ニルソンの本のセクションです。私はそれがオンラインで利用可能であることを知りませんでした。彼の本は、私がPOCO / DTO /リポジトリ/およびその他のDDD開発プラクティスで見つけた情報の最高の情報源です。


4
ブログ記事へのリンク:rlacovara.blogspot.com/2009/03/...
ジェイミー井出

28

POCOは、外部フレームワークに依存しないオブジェクトです。プレーンです。

POCOに動作があるかどうかは重要ではありません。

DTOは、ドメインオブジェクトと同様にPOCOである場合があります(通常、動作が豊富です)。

通常、DTOは通常、システムの境界で終了するため、シリアル化の目的で外部フレームワーク(属性など)に依存する可能性が高くなります。

一般的なオニオンスタイルアーキテクチャ(広くDDDアプローチでよく使用されます)では、ドメインレイヤーが中央に配置されるため、この時点では、そのオブジェクトはそのレイヤーの外部に依存関係を持つべきではありません。



6

DTOはPOCOになることができると思います。DTOはオブジェクトの使用方法に関するものであり、POCOはオブジェクトのスタイルに関するものです(アーキテクチャの概念から切り離されています)。

POCOがDTOとは異なる例の1つは、ドメインモデル/ビジネスロジックモデル内のPOCOについて話しているときです。これは、問題のドメインを表す適切なOO表現です。アプリケーション全体でPOCOを使用できますが、知識が漏洩するなどの望ましくない副作用が生じる可能性があります。DTOは、たとえば、UIが通信するサービスレイヤーから使用されます。DTOはデータのフラットな表現であり、UIにデータを提供し、変更をサービスレイヤーに通信するためにのみ使用されます。サービス層は、DTOの双方向のPOCOドメインオブジェクトへのマッピングを担当します。

更新 Martin Fowler 、このアプローチは取るに足らない道であり、ドメイン層とユーザーインターフェースの間に大きな不一致がある場合にのみ取られるべきであると述べました。


2
@David Landman、あなたが含めたリンクはローカルDTOパターン用です。これは、システム境界内の転送状態にDTOが使用される場合です。これらのケースでは、システム内に共有できる明確に定義されたドメインが既にあるはずなので、非常に注意する必要があります。システムの境界を越えて状態を転送する場合、DTOは回避するのが難しく、すべての場合に非常に適切です。
マイケルメドウズ

@Michal Meadows、そうです、リンクは実際に問題の異なるサブセットについて話します。しかし、システム境界を越えて状態を転送する場合は、変換サービスを使用して、あるコンテキストからのPOCOを別のコンテキストからのPOCOにマップする必要があると思います。または、システムレベルの境界について話しているのですか?
Davy Landman、

1

DTOの主な使用例は、Webサービスからデータを返すことです。この場合、POCOとDTOは同等です。POCOの動作は、Webサービスから返されるときに削除されるため、動作があるかどうかは問題ではありません。


5
私はあなたの答えが少し起こっていることを誤って伝えていると思います。Webサービスの場合、オブジェクトの公開状態に基づいてプロキシが生成されます。これは、DTOがPOCOとは別に作成され、POCOと同じパブリック状態になっていることを意味します。微妙に見えるかもしれませんが、重要です。その理由は、プロキシがオリジナルと同一であっても、実際には同じクラスから構築されていないためです。
マイケルメドウズ

ええと、違います。1つは、DTOを使用して、層(この場合はWebサービス)間でデータを返す/受信します。データのみがあり、動作がないため、DTOを選択します。プロキシクラスもDTOである可能性が高く、代わりにPOCOクラスを使用した場合は、プロキシが作成されたことは事実です。ただし、この場合、POCOクラスはその動作が変換されないため、事実上DTOです。今までになかった動作を見逃さないため、私はまだDTOを使用すると言います。
John Saunders、

5
**意味的に:Webサービスは、WSDLを使用してオブジェクト状態バッグを公開します。プロキシはこれらから生成されます。これらに行動を含めることはできません。Webサービスを使用する場合、オブジェクトと公開されたドメインオブジェクトの間の唯一の関係は、検査に基づいて作成された同じパブリック状態を持つことです。
マイケルメドウズ

7
@ジョン、私はあなたが過剰反応していると思います。私はあなたが正しいと言っていますが、あなたの言い回しは誤解を招くものです。「この場合、POCOとDTOは同等です。」意味的に、それは真実ではありません。POCOはDTOとして使用でき、その逆も可能ですが、それが同等であることを意味するわけではありません...両方が食料品店にあなたを運転するために使用できるとしても、自動車とピックアップトラックだけが同等です。それらは機能が重複していますが、洞察は食料品の旅行のコンテキストでさえ、F350に相当することを伝える誰かを見つけるのは難しいでしょう。
マイケルメドウズ

3
この答えは非常に間違っています。Webサービスは、1つに十分に一般的ではありません。最も重要なことは、DTOがPOCOではないことはよく確立された事実です。DTOはデータコンテナーですが、POCOはプロパティとしてのオブジェクトであり、永続性を無視します(getまたはsaveメソッドはありません)。
トムスティッケル

1

一般的なルールは次のとおりです。DTO==悪であり、過剰に設計されたソフトウェアの指標。POCO ==良い。「エンタープライズ」パターンは、Java EEの世界で多くの人々の頭脳を破壊しました。.NETランドで間違いを繰り返さないでください。


7
詳しく説明してもらえますか?DTOは、契約での実装とプラットフォームの詳細を回避するために、Webサービスからデータを返すときに必要です。
ジョンサンダース

1
はい、John DTOはあなたの言うこととうまく機能するように設計されています。しかし、残念ながら、それらはしばしば単一層のWebアプリで必要とされないときに使用され、ほとんど価値がありません。
クレイグ

9
@drscroogemcduck、おそらくDTOは最後の手段ではなく最初の手段として使用されているため、DTOが嫌いかもしれませんが、本質的に悪ではありません... 悪名高いシングルトンまたはファクトリパターンにすぎません。何が悪いのかというと、フレームワークを開発者の喉に押し付けて、すべてのDTOを作成することを強いるアーキテクトです。彼らが何をするかについては、データ転送、DTO(慎重に行われる場合)が最適です。
マイケルメドウズ

0

DTOクラスは、さまざまなソースからのデータをシリアライズ/デシリアライズするために使用されます。ソースからオブジェクトを逆シリアル化する場合、それがどの外部ソースであるかは問題ではありません。サービス、ファイル、データベースなどです。その一部のみを使用したいが、そのデータを簡単に逆シリアル化する方法が必要な場合オブジェクト。その後、そのデータを使用するXModelにコピーします。シリアライザは、DTOオブジェクトをロードするための美しいテクノロジーです。どうして?オブジェクトをロード(非直列化)するために必要な関数は1つだけです。


0

TL; DR:

DTOは、状態転送のパターンを記述します。POCOは何も記述しません。これは、OOPでの「オブジェクト」の別の言い方です。それはPOJO(Java)から来たもので、Martin Fowlerによって造られたもので、Martin Fowlerは、文字通り 'object'のより奇妙な名前として説明しています。'object 'はそれほどセクシーではないからです。

DTOは、関係するレイヤー間で状態を転送するために使用されるオブジェクトパターンです。それらは、その振る舞いが状態を変化させない限り、振る舞いを持つことができます(つまり、技術的にはpocoになることができます)。たとえば、それ自体をシリアル化するメソッドがあるとします。

POCOはプレーンオブジェクトですが、「プレーン」が意味するのは、特別なものではないということです。これは、暗黙のパターンのないCLRオブジェクトであることを意味します。総称。他のフレームワークで動作するように作られていません。[JsonProperty]たとえば、POCOにEFデコレーションがそのプロパティ全体にある場合、それはPOCOではないと主張します。

ここで、比較するさまざまな種類のオブジェクトパターンの例をいくつか示します。

  • ビューモデルビューのデータをモデル化するために使用されます。通常、バインディングと検証を支援するデータ注釈があります。MVVMでは、コントローラとしても機能します。DTOを超える
  • 値オブジェクト:値を表すために使用されます
  • 集計ルート:状態と不変条件の管理に使用されます
  • ハンドラー:イベント/メッセージに応答するために使用されます
  • 属性:横断的な懸念に対処するための装飾として使用
  • サービス:複雑なタスクを実行するために使用されます
  • コントローラ:リクエストとレスポンスのフローを制御するために使用されます
  • ファクトリー:コンストラクターが十分でないときに使用する複雑なオブジェクトを構成および/またはアセンブルするために使用されます。実行時に作成する必要があるオブジェクトを決定するためにも使用されます。
  • リポジトリ/ DAO:データへのアクセスに使用

これらはすべて単なるオブジェクトですが、ほとんどがパターンに関連付けられていることに注意してください。したがって、それらを「オブジェクト」と呼ぶか、その意図についてより具体的にして、それが何であるかによってそれを呼び出すことができます。これもデザインパターンがある理由です。いくつかの作品で複雑な概念を説明します。DTOはパターンです。集約ルートはパターンであり、ビューモデルはパターンです(MVCおよびMVVMなど)。POCOはパターンではありません。

POCOはパターンを記述しません。これは、OOPでクラス/オブジェクトを参照するための別の方法です。それを抽象的な概念と考えてください。彼らは何かを指すことができます。IMO、一方向の関係はありますが、オブジェクトが1つの目的しか果たせなくなるポイントに到達すると、POCOではなくなります。たとえば、あるフレームワークで機能するようにクラスを装飾でマークアップすると、POCOではなくなります。したがって:

  • DTOはPOCOです
  • POCOはDTOではありません
  • ビューモデルはPOCOです
  • POCOはビューモデルではありません

2つを区別するポイントは、パターンを明確にして一貫性を保ち、懸念を越えて密結合に至らないようにすることです。たとえば、状態を変更するメソッドを持つビジネスオブジェクトがあり、SQL ServerとJsonPropertyに保存するためのEFデコレーションで地獄に装飾されているため、APIエンドポイント経由で送信できるようになっているとします。そのオブジェクトは変更に耐性がなく、プロパティのバリアント(例:UserId、UserPk、UserKey、UserGuidなど)が散らばっていて、DBに保存されないようにマークされているものと、シリアル化されないようにマークされているものがあります。 APIエンドポイントでのJSON)。

ですから、何かがDTOだと言ったら、状態を移動する以外の目的でそれが使用されていないことを確認します。ビューモデルであると私に言った場合は、おそらくデータベースに保存されていないことを確認します。ドメインモデルだと言った場合は、ドメイン外の依存関係がないことを確認します。しかし、POCOであると私に言った場合、実際にはあまり私に話さないでしょう。


-13

それらをDTOと呼ばないでください。それらはモデルと呼ばれています....期間。モデルに動作はありません。だれがこのばかげた用語のDTOを思いついたのかはわかりませんが、.NETである必要があります。MVCのビューモデルについて考えてみてください。これは同じダム**のことです。モデルは、サーバー側または回線期間にわたってレイヤー間で状態を転送するために使用されます。これらはすべてモデルです。データを持つプロパティ。これらは、ワイヤーを介して渡すモデルです。モデル、モデルモデル。それでおしまい。

ばかげたDTOが私たちの語彙から消えてくれることを願っています。


1
モデルが振る舞いを持たないというこの考えがどこで得られたのかはわかりません。動作をモデル化せずに、CRUD以外のものをどのようにモデル化しますか?ViewModelでさえ、多くの場合、特にMVVMアプリで動作します。DTOは目的を正確に説明しているため、有用な用語です。データを転送します。
ジェラルド

9
事実が正しくないこと、そして価値ある態度に反対した。
joedotnot 2015

ナンセンス。モデルは愚かなコンテナである必要があります。DTOはありません、それはMSで構成された用語です。ドメイン、サービス、アプリ間でモデルを転送します。限目。DTOは不要な用語の無駄であり、混乱を招くだけです。モデル、モデル、そしてそれ以上のモデル。モデルには動作がある場合とない場合があります。ビューモデルはすべきではありません。その動作は、ModelクラスではなくBLにある必要があります。
PositiveGuy

DTOは機能的にモデルであることに同意します。ViewModelには動作があり、MVVMでバインドするものです。しかし、私は自分のモデルがよりインテリジェント(基本的にはVMですが、それよりも呼び出したくありませんでした)で、DTOオブジェクトを「受け入れる」アプリを作成しました。これにより、フレームワークでより多くのオプションを使用できるようになりました。そのため、CRUD(またはEF)からも、WCFサービスを介してオブジェクトを送信し、DTOオブジェクトを受信して​​カプセル化します(OnProp Changeを追加するなど)。私のViewModelはさらにカプセル化を実行し、「モデル」の2つ(またはリスト)を受け入れた可能性があります。厳密な定義はVMです。
SQLMason 2015

「ドメイン、サービス、アプリ間でモデルを転送します」説明する動作について、モデルという用語がDTOという用語よりも適切で適切であると考えるのはなぜですか?
caa 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.