I have an abstract class and their respective concerete implentations
public abstract class BaseEmailBuilder{
public abstract String buildBody();
public abstract String getDestinationEmail();
}
public class AppleEmailBuilder extends BaseEmailBuilder{
public abstract String buildBody(){
return "";
}
public abstract String getDestinationEmail(){
return "[email protected]";
}
}
public class OrangeEmailBuilder extends BaseEmailBuilder{
public abstract String buildBody(){
return "";
}
public abstract String getDestinationEmail(){
return "[email protected]";
}
}
public enum VendorEmailType{
APPLE("apple"),
ORANGE("orange");
}
I have a job that sends this email but I dont want the job to know anything about the concrete implementations of the email builder. The job only knows about
the VendorEmailType. So I built a factory that the job calls.
public class VendorEmailBuilderFactory{
private static final Map<VendorEmailType,
Class<?extends BaseEmailBuilder>> EMAIL_BUILDER_BY_TYPE
= new EnumMap<>(VendorEmailType.class);
static{
EMAIL_BUILDER_BY_TYPE.put(EMAIL_BUILDER_BY_TYPE.APPLE,
AppleEmailBuilder.class);
EMAIL_BUILDER_BY_TYPE.put(EMAIL_BUILDER_BY_TYPE.ORANGE,
OrangeEmailBuilder.class);
}
@Inject
private Injector injector;
public BaseThirdPartyPrivacyDeletionEmailBuilder getEmailBuilderForEmailVendorType(
VendorEmailType type){
if(!EMAIL_BUILDER_BY_TYPE.containsKey(type)){
throw new IllegalArgumentException("Could not find email builder for type=" + type);
}
return injector.getInstance(EMAIL_BUILDER_BY_TYPE.get(type));
}
}
I like that when someone sees the factory class, they can see easily read the static map to understand how the concrete implementations are linked. But Guice Injector javadocs also says :
When feasible, avoid using this method, in favor of having Guice
inject your dependencies ahead of time.
The other alternative is to inject the concrete classes in the factory and write a switch or if condition
public class VendorEmailBuilderFactory{
@Inject
private AppleEmailBuilder apple;
@Inject
private OrangeEmailBuilder orange;
public BaseThirdPartyPrivacyDeletionEmailBuilder getEmailBuilderForEmailVendorType(
VendorEmailType type){
switch(type){
case APPLE: return apple;
case ORANGE: return orange;
break;
default:
throw new IllegalStateException("Could not find email builder type=" + type);
}
}
}
I am a little torn between the approaches. Leaning towards (1) because of how easy it is to read from static map. But hesitant because of Guice advising to avoid using getInstance. Would appreciate other ideas or critiques! thank you!