はじめに
Googleが推奨する階層型アーキテクチャの中にはドメインレイヤというものがあるので調べてみた。
階層型アーキテクチャ
ドメインレイヤを除いたアーキテクチャは
View (Fragment, Activity) → ViewModel → Data Layer
の構造になっている場合が多い。
ドメインレイヤを入れる場合はRepositoryとViewModelの間に挟まってくる。
ドメインレイヤ
命名規則は ○○UseCase
ドメインレイヤは基本的にViewModelのビジネスロジックを代わりに受け持つ役割。
ViewModelが行っているRepositoryからデータを取得してUI側で利用可能なデータに変換する処理を行うパターンが多くなりそう。
Android Developerにはドメインレイヤを使うメリットとして下記のようにまとめられていた。
- コードの重複を回避できます。
- ドメインレイヤ クラスを使用するクラスの読みやすさが向上します。
- アプリのテストのしやすさが向上します。
- 役割を分担することで、クラスが大規模になることを回避できます。
ドメインレイヤの例
// 取得したアイテムの中で有効なもののみを取り出す
class GetAvailableItemsUseCase(
private val itemsRepository: ItemsRepository
) {
operator fun invoke(id: Int){
const items = itemsRepository.get(id)
return items.filter{ it.available }
}
}
上記では取得したアイテムの中でavailbaleがtrueのものだけを取り出している。
上記の処理は単純でドメインレイヤに分けるメリットは大きくないかもしれないが、このロジックが複雑になってきたり、様々な場所で再利用されるようになるとメリットは大きくなると考えられる。
また、ドメインレイヤの中で複数のリポジトリからデータを取得して1つのデータにまとめたりすることもある。
/**
* Android develoeprsのコードを引用 (<https://developer.android.com/jetpack/guide/domain-layer?hl=ja#combine-repositories>)
* This use case fetches the latest news and the associated author.
*/
class GetLatestNewsWithAuthorsUseCase(
private val newsRepository: NewsRepository,
private val authorsRepository: AuthorsRepository,
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
suspend operator fun invoke(): List<ArticleWithAuthor> =
withContext(defaultDispatcher) {
val news = newsRepository.fetchLatestNews()
val result: MutableList<ArticleWithAuthor> = mutableListOf()
// This is not parallelized, the use case is linearly slow.
for (article in news) {
// The repository exposes suspend functions
val author = authorsRepository.getAuthor(article.authorId)
result.add(ArticleWithAuthor(article, author))
}
result
}
}
マンガアプリにおけるドメインレイヤ利用例
弊社が手掛けているマンガアプリの中での利用例を考えると、作品ダウンロード機能が挙げられる。
サーバーから取得した作品一覧とローカルに保存されている作品一覧を取得し、ダウンロード済みの作品とそれ以外の作品とで表示を分けるためのデータ処理をドメインレイヤで行うことで、複数リポジトリアクセスの複雑な処理をまとめることができる。
使いどころまとめ
- 複数のRepositoryを組み合わせる場合
- 複雑になりがちなので、UseCaseにまとめるのが良いと思われる
- フロント側で複雑なデータ変換処理を行う場合
- 特にローカルで持っているデータを使ってリモートのデータを加工する場合
- 同じ処理を何度も再利用する場合