jstuyts-squins
10/20/2017, 8:52 AMdave08
10/20/2017, 11:50 AMjstuyts-squins
10/20/2017, 6:53 PMclass TheFunctionClient(private val isInternetConnectionAvailable: () -> Boolean)
class TheFunctionClient(private val internetConnectionAvailability: InternetConnectionAvailability)
dave08
10/21/2017, 4:55 PMjstuyts-squins
10/23/2017, 4:53 AMdave08
10/27/2017, 11:40 AMjstuyts-squins
10/27/2017, 11:57 AMdave08
10/28/2017, 7:19 PMjstuyts-squins
10/30/2017, 8:56 AMUserRepo
and JdbcUserRepo
. The view class of the profile page requires an instance of UserRepo
to get and update information (note: the syntax of the examples below may not be correct):
class ProfilePage @Inject constructor (val userRepo: UserRepo) { ... }
Now, you need to add a caching decorator:
class CachingUserRepo @Inject constructor (val delegatee: UserRepo) : UserRepo { ... }
Things start to break down at this moment. Most DI containers will start complaining that there are multiple implementations of UserRepo
. A container is unable to decide which implementation has to be injected into which client.
Well, qualifiers to the rescue:
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class Caching
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class Jdbc
And here comes the violation of the open-closed principle. You have to modify existing classes simply because you want to have it talk to another implementation:
@Caching
class CachingUserRepo @Inject constructor (@Jdbc val delegatee: UserRepo) : UserRepo { ... }
@Jdbc
class JdbcUserRepo @Inject constructor(...) : UserRepo { ... }
class ProfilePage @Inject constructor (@Caching val userRepo: UserRepo) { ... }
Now imagine you have another decorator that you want to add to 1 context (e.g. production), but not another (e.g. test). Which qualifiers do you have to write? And which classes and which parameters should have which qualifiers?dave08
10/30/2017, 9:05 AMjstuyts-squins
10/30/2017, 9:41 AMjstuyts-squins
10/30/2017, 9:41 AMdave08
11/01/2017, 10:22 PMdave08
11/01/2017, 10:23 PM