ドメイン層を純粋に〜リポジトリ都合の実装をドメイン層から剥がす〜Zennかきあげせいろ🏗️ドメイン層を純粋に〜リポジトリ都合の実装をドメイン層から剥がす〜2024/10/06に公開2024/10/07Java関数型プログラミングリファクタリングドメイン駆動設計techDDDでリポジトリの実装の都合がドメイン層に書かれてしまう問題ドメイン駆動設計(DDD)では、リポジトリの実装の都合がドメイン層に書かれてしまうと、ドメインで表現したかったことにシステムの都合が混在する形になり、DDDのメリットを100%発揮できなくなってしまいます。この問題を解決するために、Javaの関数型インターフェース、特にConsumerを使ったリファクタリング方法を紹介します。Consumerとラムダ式を使うことで、ドメイン層とリポジトリの実装を引き離し、堅牢な設計が可能になります。具体的な例を使って、コードの改善プロセスを一緒に見ていきましょう。Consumerとは関数型インターフェースは、ラムダ式を使って簡潔に処理を記述できる便利な仕組みです。中でもConsumer<T>は、1つの引数を受け取って何らかの処理を行うインターフェースで、戻り値はないシンプルなインターフェースです。Consumer<String>は「文字列を受け取って何かを行う処理」を定義できます。System.out.println(message);printer.accept("コンニチワ!!");リポジトリの実装の都合が、ドメイン層に書かれている例Consumerを学んだので、リポジトリの実装の都合がドメイン層に書かれてしまったコードを見てみましょう。なんらかのコンテンツを操作するContentRepositoryインターフェースとその実装クラスContentRepositoryImplがあるとします。fetchContents();}実装クラスは外部APIを利用してデータを取得する処理をします。外部APIの仕様上、1回のリクエストで最大100件のデータしか取得できません。}}そしてリポジトリを利用する側の処理であるContentServiceがあるとします。3回ループする必要がある。これにより、ドメイン層にリポジトリの実装詳細が漏れてしまう。}}Consumerを使ったリファクタリングConsumerを使ってリポジトリの実装の都合による実装(3回ループする部分)をContentRepositoryImplに移動します。ContentRepositoryのコードをリファクタリングして、取得したコンテンツに対する処理を外部から渡せるように変更します。count);}そしてContentRepositoryImplも合わせて変更します。引数にConsumerと件数をとるようになった。戻り値が呼出し側で不要になったのでvoidにし、メソッド名も変更した。300件を取得する実装はこのメソッドでやるようにした。}}変更したリポジトリを利用するコードも変更します。}}まとめこの記事では、リポジトリの実装の都合がドメイン層に書かれてしまう問題に焦点を当て、Javaの関数型インターフェースであるConsumerを活用して、これを解決する方法を紹介しました。外部APIの仕様により、ドメイン層のContentServiceクラスで複数回のAPI呼び出しを直接行い、その結果、ドメイン層にリポジトリの実装詳細が漏れ出すという問題がありました。この問題に対しConsumerを使うことで、取得したコンテンツに対する処理をリポジトリ側で柔軟に受け渡しできるようにリファクタリングしました。これにより、ContentServiceはAPIの呼び出し回数やデータ取得のロジックを気にせず、純粋にドメイン層のロジックに集中することができました。他の関数型インターフェースの紹介Consumer以外にも便利な関数型インターフェースがいくつかあり、これらをうまく使うことで、さらに柔軟にコードを書くことができます。引数を取らずに、何らかの値(T型)を返すインターフェースです。引数として1つの値(T型)を受け取り、結果(R型)を返すインターフェースです。データの変換やマッピングに便利です。引数を1つ受け取り、その条件に基づいてtrueかfalseを返すインターフェースです。streamのfilterで指定するやつです。2つの引数を受け取り、何らかの処理を行うインターフェースです。Proよくある質問LinksX(Twitter)GitHubメディアキットLegal利用規約プライバシーポリシ。