コンテンツにスキップ

ダブルディスパッチの記事を更新しました

エンティティがドメインサービスに依存!?ダブルディスパッチとは? のドキュメントを、このブランチで大幅に更新しました。

以前は概念の説明が中心だった記事を、図やコード例を交えた「読んで実装に活かせる」内容に仕上げ直しています。

ダブルディスパッチは「一時的な依存の逆転」という性質がポイントですが、文章だけだと通常の依存関係との違いが伝わりにくいと感じていました。

また、どの場面で採用すべきか・避けるべきかの判断基準や、具体的なコードがなかったため、学習用のアウトプットとしてはまだ不十分な状態でした。今回の更新で、そのあたりを補完しています。

次の図を新たに追加しました。

  • ドメイン層の基本的な依存関係 — エンティティ、値オブジェクト、ドメインサービス、リポジトリ IF の関係を一覧化
  • 通常の依存関係とダブルディスパッチ実行時の比較 — コード上の依存と、メソッド呼び出し時だけ生じる一時的な逆転を対比
  • 問題のある実装とダブルディスパッチ実装の呼び出しフローaddMember / joinMember / verifyCanJoin を使った比較図

図が読みやすくなるよう、サイト側でも Mermaid の表示設定(フォントサイズや余白)と CSS を調整しています。

  • 「一時的な依存の逆転」という表現を明確化し、恒久的な設計変更ではないことを強調
  • ルール漏れが起きうる「基本的な依存関係」の問題点を、フローチャートで整理
  • ダブルディスパッチによって「アプリケーションサービスが検証を忘れる」ミスを構造的に防げる理由を追記

新セクション 「ダブルディスパッチを使用すべきケースと避けるべきケース」 を追加しました。

採用を検討したい場面(集約外の情報が必要、ルール漏れが致命的、など)と、無理に使わなくてよい場面(集約内で完結するルール、運用で十分な場合、など)を箇条書きでまとめています。

「パーティーにプレイヤーを参加させる」という例で、次の 2 パターンを Kotlin で掲載しています。

  1. 問題のある実装Party.addMember が public のまま、検証をバイパスできてしまうケース
  2. ダブルディスパッチの実装joinMember 内で PartyMembershipService を呼び、検証を必ず通すケース

ファクトリメソッド create からも同じ joinMember を経由する構成にし、生成・変更の両方でルールが適用されることを示しています。

次のトピックを追記しました。

  • 一時的な依存の逆転であることを忘れない
  • ドメインサービスは状態を持たない
  • 引数として渡すことで意図を明示する
  • DB からの再構築(リハイドレーション)とは別問題

最後に、記事全体のポイントを 3 つに整理したまとめセクションも加えています。

DDD まわりのドキュメントは、引き続き実務で使う知識を自分の言葉で整理しながら充実させていく予定です。

ダブルディスパッチの記事を読んで気づきやフィードバックがあれば、ぜひ教えてください。