I have module A and module B each one have some specific services and i have a module C that don’t have any dependencies to A and B so what i want is to call services from modules A and B and I want to acheive that using factory pattern.
in module C i have created this interface and it will be a common interface to be implemented in modules A and B
public interface ThirdPartyCallsStrategy {
void apply(String orderId);
}
And this is example of factory class and will provide the appropriate instance needed based on type parameter
@Component
@AllArgsConstructor
public class CoreCallsFactory {
private static final String A_PACKAGE = "com.testA.service";
private static final String A_CLASS = "TestClassA";
private static final String B_PACKAGE = "com.testB.service";
private static final String B_CLASS = "TestClassA";
@SneakyThrows
public ThirdPartyCallsStrategy createThirdPartyCallsStrategy(String type) {
Class<?> clazz;
if (type.equals("A")) {
clazz = Class.forName(String.format("%s.%s", A_PACKAGE , A_CLASS ));
return (ThirdPartyCallsStrategy) clazz.getDeclaredConstructor().newInstance();
}
if (type.equals("B")) {
clazz = Class.forName(String.format("%s.%s", B_PACKAGE , B_CLASS ));
return (ThirdPartyCallsStrategy) clazz.getDeclaredConstructor().newInstance();
}
return null;
}
}
ThirdPartyCallsStrategy
is implemented in different services in different modules
And finally in module C, i make the instanciation through java reflection but this will be at runtime and it can through exceptions later at runtime and not at compile time
public String checkStatusAndRedirect(String orderId, String type) {
boolean status = checkStatus(orderId);
StringBuilder paymentResultUrl = new StringBuilder(frontUrl + "/public/payment/status?success=");
if (status) {
coreCallsFactory.createThirdPartyCallsStrategy(type).apply(orderId);
paymentResultUrl.append(Boolean.TRUE);
} else {
paymentResultUrl.append(Boolean.FALSE);
}
return paymentResultUrl.toString();
}
So what i need is a cleaner way to change this implementation.
The best way to do this is like:
public interface FactoryProducer<T> {
public T create(String param);
}
public class Factory<T> {
Map producers = new HashMap<string, FactoryProducer<T>>();
public void registerFactory(String key, FactoryProducer<T> producer) {
producers.put(key, producer);
}
public Factory<T> getFactory(String key) {
return producers.get(key);
}
}
This way you can build FactoryProducers and Factories and keep everything decoupled.
Maybe use a
Map<String,String>
that maps from thetype
to the format string generated byString.format("%s.%s", A_PACKAGE , A_CLASS )
andString.format("%s.%s", B_PACKAGE , B_CLASS )
respectively?It’s always possible to do better, but what do you really mean by “cleaner way”?
i don’t want to work with java reflection due to its performance degradation problem