Skip to content

エンティティがドメインサービスに依存!?ダブルディスパッチとは?

今回の記事ではエンティティがドメインサービスに一時的に依存するダブルディスパッチという手法について解説していきたいと思います。

DDDのドメインサービスとエンティティの関係、ダブルディスパッチの関係を具体的なコードを見ながら解説していきたいと思います。

DDDにおけるドメイン層の基本的な依存関係

Section titled “DDDにおけるドメイン層の基本的な依存関係”

まずはDDDにおけるドメイン層の基本的な依存関係を見ていきましょう。

1. エンティティ → 値オブジェクト

Section titled “1. エンティティ → 値オブジェクト”

まずは最も基本的な部分です。 エンティティは属性を表現するために値オブジェクトを持つことがあります。 そのためエンティティは値オブジェクトに依存することになります。

逆に値オブジェクトはドメインの最小単位的な役割を持っており他の何者にも依存しないのが理想です。

2. ドメインサービス → エンティティ / 値オブジェクト

Section titled “2. ドメインサービス → エンティティ / 値オブジェクト”

ドメインサービスはドメインの調整役と言われるだけあってエンティティや、値オブジェクトを扱います。 そのため依存関係としてはエンティティと値オブジェクトに依存する形となります。

3. リポジトリ(IF) → エンティティ / 値オブジェクト

Section titled “3. リポジトリ(IF) → エンティティ / 値オブジェクト”

リポジトリのインターフェースもエンティティや値オブジェクトに依存します。 リポジトリは引数としてエンティティや値オブジェクトを受け取って、それをDBに保存すると考えると当然ですね。

ではここから本題のダブルディスパッチについてみていきたと思います。

ダブルディスパッチとは、「ある集約ルートのメソッドが、ドメインサービスを引数として受け取り、サービスの知識を用いて処理を完成させる」という手法です。

つまり依存関係は「エンティティ → ドメインサービス」となります。

エンティティの生成・変更にエンティティの外部の値が必要で、かつ絶対にルールを守ってもらう必要がある場合に使用します

エンティティの外部の値が必要というのはドメインサービスと集約ルートの使い分けに関わってきますが、その説明は長くなってしまうため今回は割愛します

ということでルールを確実に守るとはどういうことなのかをみていきます。

基本的な依存関係の場合、実装者によっては致命的なルールの漏れが発生してしまう場合があります。

「アプリケーションサービスからドメインサービスのメソッドを使用し、エンティティを生成・変更 そして、リポジトリ経由でDBに保存する」と言った流れになります。

ただエンティティの実装内容によってはドメインサービスの処理をバイパスできてしまいます。

実装者が誤って「アプリケーションサービスからエンティティを生成・変更し、リポジトリ経由でDBに保存する」というようにドメインサービスの処理を飛ばしてしまった際、もちろんですがドメインサービスの処理は飛ばされ、そこに記載されていたルールは完全に無視されてしまうのです。

エンティティのファクトリメソッドや、変更メソッドの引数にドメインサービスを渡しその中でドメインサービスのメソッド(チェックメソッドなど)を実行するように実装します。

すると、エンティティを生成・変更するたびにドメインサービスのメソッドが実行されることとなります。 結果、実装者がドメインサービスの存在に気が付かず実装に誤りがあったとしても確実にドメインサービスのルールを満たすことができるようになります。

ダブルディスパッチを使用すべきケースと避けるべきケース

Section titled “ダブルディスパッチを使用すべきケースと避けるべきケース”