Data Transfer Object
An object that carries data between processes in order to reduce the number of method calls.
-
Remote Facade(未習)等のリモートインタフェース利用時はコール回数を少なくしたい
- レイテンシ大きいため
- 過不足ないデータを取得するために何回もコールしてしまうより、1回のコールでデータを取りすぎるほうがマシ
- コール回数を減らすためには、1コールあたりのデータ転送量を増やす必要がある
- 戻り値が1つしかない言語では複数のオブジェクトを返せない
- Data Transfer Objectにシリアライズして返す
-
Java界隈ではこのオブジェクトのことを「Value Object」と呼ぶ
- PoEAA的にはValue Objectは全く別のパターン
How It Works
-
Data Transfer Objectは、普段は忌み嫌われるたぐいのオブジェクト
- フィールドとgetter/setterが生えてるだけ
- 振る舞いなし
-
N/W越しに1コールで複数の情報を転送できることに価値がある
- 分散システムで必要
-
Domain Modelは複雑に絡み合ったグラフ構造になっており、そのままではシリアライズできない
- 循環参照があったりする
-
比較的単純なData Transfer Objectに詰めなおしてシリアライズする
- 階層構造
- プリミティブ型、または別のDTOのみ集約する
-
クライアントごとに別のDTOを作ることはままある
- Webページ用
- GUI用
-
何種類作るの
- one size fits allな答えはない
- データに共通点が多ければ1つ
- 一部のrequest/responseだけデータの共通点が無かったりしたら分ける
-
request/responseで分ける?共通?
- one size fits allな答えはない
- 全然違えば分ける
-
immutableにする?mutableにする?
-
派閥
- requestで渡されたオブジェクトと全く同じものを返却する場合でも、新しいものを生成して返す派
- requestで渡されたオブジェクトをmodifyして返す派
- 著者は「どちらがよい」という意見はない
-
が、便利のためにmutableを好む
- 「新しいものを生成して返す」場合でも、少しずつ構築できる
-
(PoEAAの)Value Objectパターンとの混同も関連する話題
- Value Objectはimmutable
-
-
Record SetはまさにDTO
- RDBというリモートインタフェース用のDTOだといえる
-
汎用コレクションにする?専用クラスにする?
-
汎用コレクション
-
配列はよくない
- コードが不明瞭になる
-
辞書がよい
- 意味のあるキーを指定できる
-
- コード生成が利用できない場合は汎用コレクションの利用価値あり
-
コード生成が利用できるなら専用のクラスを作るべき
- DTOをコンポーネント間のプロトコルとして使う場合は尚更
-
Serializing the Data Transfer Object
- DTOは、getter/setterに加えて、自身のシリアライジングの責務ももつ
- ビルトインのシリアライズがあればそれを使うと良い(json,xml等)
- レコード定義からコード自動生成できると良い
- シリアライズ形式をどうする?(テキスト/バイナリ)
テキスト | バイナリ | |
---|---|---|
可読性 | o | x |
帯域幅節約 | x | o |
DTO定義の変化への耐性 | o | x |
- 理論的には、送信側と受信側でDTOのクラス定義が同期しているべき
- 実際には同期しなくなることがある
- 専用のクラスを作る場合で、バイナリにシリアライズする場合は、送信側/受信側でクラス定義が同期していないと、デシリアライズ時にエラーが発生する
-
汎用の辞書を使うことでエラー耐性を持たせることができる
- 【補】キーが増えても辞書は辞書
Assembling a Data Transfer Object from Domain Objects
- Domain ModelとDTOとの相互変換
-
Domain ModelとDTOとは依存させなくない
-
Domain Model <— DTO
- Domain Objectの定義はN/Wの両サイド、システムごとにで異なるため、依存するわけにはいかない
-
Domain Model —> DTO
- Domain Modelは外部インタフェースからの影響をうけたくない
-
-
Assemblerクラスを導入して依存を切り離す
- 要するにMapperパターン
When to Use It
-
2つのプロセス間で、1回のメソッドコールで複数のデータアイテムを転送する必要がある時に
-
代替案
-
戻り値が1つしかない問題への対処 — 戻り値を使わない
- 引数をたくさん取るsetterを生やす
-
引数で複数のオブジェクトを返却するgetterを生やす
- 【補】.NETのout引数
-
DTOではなく、文字列表現をそのまま転送する
- 文字列表現にすべてが依存するのでよくない
-
explicitなインタフェース = クラスを使用する利点は、実装を隠蔽できること
- 文字列
- バイナリ
-
-
-
XMLはDTOにパースするのがよい
- DOM操作は痛みを伴う
-
DTOでカプセル化することで生成を簡単にする
- 【補】XMLをそのまま使おうとすると、パーサやらなんやら構築しないといけない
-
レイヤー間の疎通の抽象化
-
UI側は、Record Set (DTOの一種)の扱い方だけを知っている
- DBから得られたRecord Setなのか、他のレイヤーで加工されたRecord Setなのか意識しない
-
Further Reading
-
Assembler
- 名前の出処: Alur et al.
- Mapperの一種なので独立したパターンとしては掲載していない
-
DTOという命名、Value Objectとの名前衝突の解決
-
多数決に従った
- 「PoEAAのDTO」のことを指して「Value Object」と呼ぶのはJ2EEコミュニティのみ
-
多くの人々にとって「Value Object」は別のパターンだった
- 「PoEAAのValue Object」はこちらを指すことに
-
Example: Transferring Information About Albums (Java)
略
Example: Serializing Using XML (Java)
略
英語
-
blanket rule
- どんなときにも適用できるルール