Java Factory pattern

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.

  • Maybe use a Map<String,String> that maps from the type to the format string generated by String.format("%s.%s", A_PACKAGE , A_CLASS ) and String.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

    – 




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.

Leave a Comment