エンティティがドメインサービスに依存!?ダブルディスパッチとは?
今回の記事ではエンティティがドメインサービスに一時的に依存するダブルディスパッチという手法について解説していきたいと思います。
DDDのドメインサービスとエンティティの関係、ダブルディスパッチの関係を具体的なコードを見ながら解説していきたいと思います。
DDDにおけるドメイン層の基本的な依存関係
Section titled “DDDにおけるドメイン層の基本的な依存関係”まずはDDDにおけるドメイン層の基本的な依存関係を見ていきましょう。
1. エンティティ → 値オブジェクト
Section titled “1. エンティティ → 値オブジェクト”まずは最も基本的な部分です。 エンティティは属性を表現するために値オブジェクトを持つことがあります。 そのためエンティティは値オブジェクトに依存することになります。
逆に値オブジェクトはドメインの最小単位的な役割を持っており他の何者にも依存しないのが理想です。
2. ドメインサービス → エンティティ / 値オブジェクト
Section titled “2. ドメインサービス → エンティティ / 値オブジェクト”ドメインサービスはドメインの調整役と言われるだけあってエンティティや、値オブジェクトを扱います。 そのため依存関係としてはエンティティと値オブジェクトに依存する形となります。
3. リポジトリ(IF) → エンティティ / 値オブジェクト
Section titled “3. リポジトリ(IF) → エンティティ / 値オブジェクト”リポジトリのインターフェースもエンティティや値オブジェクトに依存します。 リポジトリは引数としてエンティティや値オブジェクトを受け取って、それをDBに保存すると考えると当然ですね。
ダブルディスパッチとは
Section titled “ダブルディスパッチとは”ではここから本題のダブルディスパッチについてみていきたと思います。
一時的な依存の逆転
Section titled “一時的な依存の逆転”ダブルディスパッチとは、「ある集約ルートのメソッドが、ドメインサービスを引数として受け取り、サービスの知識を用いて処理を完成させる」という手法です。
つまり依存関係は「エンティティ → ドメインサービス」となります。
どういった時に使用するのか
Section titled “どういった時に使用するのか”エンティティの生成・変更にエンティティの外部の値が必要で、かつ絶対にルールを守ってもらう必要がある場合に使用します
エンティティの外部の値が必要というのはドメインサービスと集約ルートの使い分けに関わってきますが、その説明は長くなってしまうため今回は割愛します
ということでルールを確実に守るとはどういうことなのかをみていきます。
基本的な依存関係の場合
Section titled “基本的な依存関係の場合”基本的な依存関係の場合、実装者によっては致命的なルールの漏れが発生してしまう場合があります。
「アプリケーションサービスからドメインサービスのメソッドを使用し、エンティティを生成・変更 そして、リポジトリ経由でDBに保存する」と言った流れになります。
ただエンティティの実装内容によってはドメインサービスの処理をバイパスできてしまいます。
実装者が誤って「アプリケーションサービスからエンティティを生成・変更し、リポジトリ経由でDBに保存する」というようにドメインサービスの処理を飛ばしてしまった際、もちろんですがドメインサービスの処理は飛ばされ、そこに記載されていたルールは完全に無視されてしまうのです。
ダブルディスパッチの場合
Section titled “ダブルディスパッチの場合”エンティティのファクトリメソッドや、変更メソッドの引数にドメインサービスを渡しその中でドメインサービスのメソッド(チェックメソッドなど)を実行するように実装します。
すると、エンティティを生成・変更するたびにドメインサービスのメソッドが実行されることとなります。 結果、実装者がドメインサービスの存在に気が付かず実装に誤りがあったとしても確実にドメインサービスのルールを満たすことができるようになります。