読者です 読者をやめる 読者になる 読者になる

実践ドメイン駆動設計 第11章 ファクトリ メモ

開発 DDD

実践ドメイン駆動設計

実践ドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計

  • DDDのパターンの中で、ファクトリは最も有名なもののひとつ
  • ドメインモデルでファクトリを使えるようになるためのサンプルを示す

11.1 ドメインモデルにおけるファクトリ

  • ファクトリを使う最大の動機
  • 特定の型の集約をインスタンス化するだけで、他に責務がないオブジェクトはそのモデルの一級市民でない
    • つまり、単純なファクトリクラスはドメインモデルではない
  • 集約ルートが別の方の集約や別のパーツのインスタンスを作るファクトリメソッドを持つこともある
    • この場合も集約ルートの責務は、集約の振る舞いを提供すること
    • ファクトリメソッドは集約の振る舞いのひとつ
    • 今回はこれがよく出てくる
  • 集約の構造の重要な詳細は、間違った状態に変更されないためにも保護しておく必要がある
    • 例:あるテナントが集約をつくるとき、間違ったTenantIdを設定しまわないようにする
    • ファクトリメソッドの意義は、正しい条件で不変条件を満たしたインスタンスを作る
  • 集約にファクトリメソッドを持たせる => コンストラクタのみでは表現できないユビキタス言語を表現できる
  • 境界づけられたコンテキストの統合のときには、サービスがファクトリとして機能する
  • アブストラクトファクトリ
    • クラス階層内のさまざまな型のオブジェクトをつくる、昔ながらの使い方
    • ドメインモデリングするときに、クラス階層が登場した場合は、リボジトリの議論を参照

11.2 集約ルート上のファクトリメソッド

  • これまでの議論で出てきた、3つの境界づけら得れたコンテキスト内の、集約のルート上にある幾つかのファクトリ
    • これは本文参照
    • Productのファクトリメソッド(planBacklogItem()など)は10章で説明済み
    • コラボレーションコンテキストの3つのメソッドを取り上げる

CalendarEntryのインスタンスの作成

  • CalendarのなかでCalendarEntryのインスタンスを作るためのもの
    • テストコードは書籍参照
  • テストコードでは識別子とインスタンスがそれぞれnullでないことをチェック
  • ファクトリメソッドscheduleCalendarEntryの実装
  • シナリオを検討した結果、CalendarEntryのpublicなコンストラクタだけではモデルの表現力が損なわれる
    • ユビキタス言語に沿った設計にするため、コンストラクタをprotectedにする
    • Calendarのファクトリメソッドを必ず使わせるようにする
      • クライアントから使う際の負担も軽減
      • パフォーマンスは注視する必要があり
    • CalendarEntryが必要とするコンストラクタの引数が11 => 9に
      • 9つはクライアントが用意する
      • 2つ、TenantとCalendarIdはファクトリメソッドで用意
        • 正しいものが設定されることを保証する

Discussionのインスタンスの作成

11.3 ファクトリとしてのサービス

  • 第13章で改めて議論する
    • ここではファクトリそのものについてと、サービスをファクトリとして設計する方法について説明
  • CollaboratorServiceの形式のファクトリ
    • テナントとユーザの識別子を渡してCollaboratorのインスタンスを生成
    • コラボレーションコンテキストのドメインにおける人を表す言葉、投稿者・作成者・モデレータ・所有者・参加者の生成
      • 投稿者などは値オブジェクトとして扱う
    • インターフェイスを定義、具象クラスで実装
      • 実装はインフラストラクチャレイヤのモジュールに配置する
      • 実装ではUserInRoleAdaptorでTenantとその識別子からAuthorクラスのインスタンスに変形する
        • アダプターパターン
        • 認証・アクセスコンテキストの公開ホストサービスとやり取りして、ユーザのロールがAuthorかチェック
      • コラボレーションコンテキストではCollaboratorのidentity属性にusernameを使う
    • インスタンスのライフサイクルと概念的な用語を2つの境界づけられたコンテキストから切り離すためにサービスベースのファクトリを利用した