TRY ANDROID DEV

Android アプリ開発のコーディングネタ。あとエンジニアとしての活動

Dagger2でDIする際、インスタンス生成時にパラメータを設定したい

背景

以下のクラスを考える。

f:id:off2white:20190104132506j:plain

ここではパラメータが二つあるが、それぞれ意味合いが異なる。

このクラスのインスタンスを生成すると以下のようになるが、意味合いが異なる二つのパラメータを同時に指定していて気持ち悪かった。

val website = WebSite("google.co.jp", NarouRepository())

そのため、以下のように実装したい。

  • repositoryはDagger2によって自動的に依存性を注入したい。
  • domainは生成時に指定したい。

環境

実装

以下の3クラスで構成する。

DomainComponent

@Component(modules = [RepositoryModule::class, ApiModule::class])
interface DomainComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun domain(domain: String): Builder
        fun build(): DomainComponent
    }

    fun inject() : WebSite
}

WebSite

class WebSite @Inject constructor(val domain: String, private val searchRepository: ISearchRepository) {

    fun search(word: String): List<NovelIntroduction> {
        return searchRepository.search(word)
    }
}

ShowNovelListUseCase

class ShowNovelListUseCase {

    fun getNovelList(word: String): List<NovelIntroduction> {
        val webSite = DaggerDomainComponent.builder()
            .domain("https://api.syosetu.com/")
            .build()
            .inject()

        return webSite.search(word)
    }

}

解説

Dagger2でインスタンスにパラメータを設定する場合は@BindsInstantceを利用する。
また、パラメータを設定するためのBuilderクラスは@Component.Builderで指定できる。

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun domain(domain: String): Builder
        fun build(): DomainComponent
    }

Builderパターンを用いるため、パラメータを設定するメソッドはBuilderを返却している。
また、injectメソッドがDIの発火元であることは変わらないため、build()は対象コンポーネントを返却するように実装する。
あとは通常のComponentクラスと同様である。

DI対象のWebSiteは通常のコンストラクタインジェクションの実装でよい。

class WebSite @Inject constructor(val domain: String, private val searchRepository: ISearchRepository) {

    fun search(word: String): List<NovelIntroduction> {
        return searchRepository.search(word)
    }
}

利用する側のUsecaseは以下のように実装する。
Componentクラスで実装したBuilderを用いてWebSiteインスタンスを生成する。

    fun getNovelList(word: String): List<NovelIntroduction> {
        val webSite = DaggerDomainComponent.builder()
            .domain("https://api.syosetu.com/") // 生成時にドメインを指定する
            .build() // DomainComponentを生成する
            .inject() // inject実施。repositoryを注入する。

        return webSite.search(word)
    }

これで生成時にパラメータを指定し、本質的でない依存性の注入のみDaggerに任せることができた。