Dagger2でDIする際、インスタンス生成時にパラメータを設定したい
背景
以下のクラスを考える。
ここではパラメータが二つあるが、それぞれ意味合いが異なる。
このクラスのインスタンスを生成すると以下のようになるが、意味合いが異なる二つのパラメータを同時に指定していて気持ち悪かった。
val website = WebSite("google.co.jp", NarouRepository())
そのため、以下のように実装したい。
- repositoryはDagger2によって自動的に依存性を注入したい。
- domainは生成時に指定したい。
環境
- Android Studio 3.2
- kotlin 1.3.11
- Dagger2.19
実装
以下の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 }
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に任せることができた。