body: String) } class SMTPMailer(private val host: String): Mailer { override fun sendEmail(subject: String, to: String, body: String) { // call some SMTP server } } class NoOpMailer: Mailer { override fun sendEmail(subject: String, to: String, body: String) { // nothing! } }
a class Benefits: separation of concerns, configuration of a dependency Dependency inversion: abstraction to not depend on a specific implementation Benefits: switch implementation for different configurations / tests etc
• Runtime vs compile time validation • In essence still “pulling” dependencies, tighter coupling vs annotations (testing?) • Scoping is possible, but manual like w/ Dagger
safety • @Inject vs by inject() • Android constructs like viewModels() just work • Built-in Android aware scoping (if you need it) • Aggregation of modules (Koin annotations also introduced this)
{ @Provides @Singleton // there's probably no need to make Mailer singleton here fun provideMailer(): Mailer = if (BuildConfig.DEBUG) { NoOpMailer() } else { SMTPMailer("mail.mydomain.nl") } }
{ @Provides @Singleton // there's probably no need to make Mailer singleton here fun provideMailer(): Mailer = if (BuildConfig.DEBUG) { NoOpMailer() } else { SMTPMailer("mail.mydomain.nl") } }