PoEAA ch15 Data Transfer Object

PoEAA勉強メモ

出典: 


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

    • どんなときにも適用できるルール