Inside a module, if I need to provide a different implementation of an interface based on a variable known at module construction time I can put the logic inside the @Provides method for that interface type. Like so:
@Module
public class FooModule {
private final State state;
public FooModule(State state) {
this.state = state;
}
@Provides
FooInterface provideFooImplementation() {
switch(state) {
case STATE_1:
return new FooImpl1();
case STATE_2:
return new FooImpl2();
...
case STATE_10:
return new FooImpl10();
}
}
}
However, these implementations could be created by Dagger. I would rather say "Hey, based on X I want you to instantiate this class for me"
I have considered a couple of options.
Change the provides method to take in all of the possible implementations:
@Provides FooInterface provideFooImplementation(FooImpl1 impl1, FooImpl2 imp2, ..., FooImpl10 impl10) { switch(state) { case STATE_1: return impl1; case STATE_2: return impl2; ... case STATE_10: return impl10; } }
This allows Dagger to instantiate them and satisfy all of their dependencies but it's not a good idea if each of the implementations is relatively large or expensive to create.
Change the provides method to take in a collection of all of the dependencies for the different implementations.
@Provides FooInterface provideFooImplementation(Context context, Repo repo, HttpClient httpClient, ...) { switch(state) { case STATE_1: return new FooImpl1(context); case STATE_2: return new FooImpl2(repo, httpClient); ... case STATE_10: return new FooImpl10(context, repo); } }
This is slightly better than option 1 in that Dagger doesn't have to instantiate every single implementation, however it still needs to instantiate all of the dependencies even though they might not be used in all cases. I'm also back to creating the objects myself even though they could be created by Dagger.
Create one module per implementation and instantiate the appropriate module. So something like:
@Module public FooImpl1Module { @Provides FooInterface provideFooImplementation(Context context) { return new FooImpl1(context); } }
This would be fine, but now I have issues defining the component that depends on the module.
What's the best way to tackle this problem?
One suggestion has been to try option 1 with the parameters wrapped in Lazy. Then I only end up calling .get() on one. I'll try this out when I can and post the results