So, consider an interface called MarketPlace having two implementations, an AndroidMarketPlace and AppleMarketPlace:
interface MarketPlace {
}
class AppleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "apple";
}
}
class GoogleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "android";
}
}
and consider a user of these implementations:
class MarketPlaceUser {
private final MarketPlace marketPlace;
public MarketPlaceUser(MarketPlace marketPlace) {
System.out.println("MarketPlaceUser constructor called..");
this.marketPlace = marketPlace;
}
public String showMarketPlace() {
return this.marketPlace.toString();
}
}
A good way for MarketPlaceUser to disambiguate between these implementations is to use a guice feature called Binding Annotations. To make use of this feature, start by defining annotations for each of these implementations this way:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
@interface Android {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
@interface Ios {}
and inform the Guice binder about these annotations and the appropriate implementation corresponding to the annotation:
class MultipleInstancesModule extends AbstractModule {
@Override
protected void configure() {
bind(MarketPlace.class).annotatedWith(Ios.class).to(AppleMarketPlace.class).in(Scopes.SINGLETON);
bind(MarketPlace.class).annotatedWith(Android.class).to(GoogleMarketPlace.class).in(Scopes.SINGLETON);
bind(MarketPlaceUser.class).in(Scopes.SINGLETON);
}
}
Now, if MarketPlaceUser needs to use one or the other implementation, this is how the dependency can be injected in:
import com.google.inject.*;
class MarketPlaceUser {
private final MarketPlace marketPlace;
@Inject
public MarketPlaceUser(@Ios MarketPlace marketPlace) {
this.marketPlace = marketPlace;
}
}
This is very intuitive. If you have concerns about defining so many annotations, another approach could be to use @Named built-in Google Guice annotation, this way:
class MultipleInstancesModule extends AbstractModule {
@Override
protected void configure() {
bind(MarketPlace.class).annotatedWith(Names.named("ios")).to(AppleMarketPlace.class).in(Scopes.SINGLETON);
bind(MarketPlace.class).annotatedWith(Names.named("android")).to(GoogleMarketPlace.class).in(Scopes.SINGLETON);
bind(MarketPlaceUser.class).in(Scopes.SINGLETON);
}
}
and use it this way, where the dependency is required:
import com.google.inject.*;
class MarketPlaceUser {
private final MarketPlace marketPlace;
@Inject
public MarketPlaceUser(@Named("ios") MarketPlace marketPlace) {
this.marketPlace = marketPlace;
}
}
If you are interested in exploring this further, here is the Google guice sample and an equivalent sample using Spring framework
No comments:
Post a Comment