2

I have an api which has some base implementations. I have a factory which gives the instances of that api to the clients.

I want to change my factory to make it more generic so, if a new implementation of the api will be generated and its jar file will be put in classpath, the factory will understand it and any changes wouldn't be needed.

Laurentiu L.
  • 6,566
  • 1
  • 34
  • 60
A.v
  • 734
  • 5
  • 26

2 Answers2

4

Use the java SPI, Service Provider Interface.

  • API jar - Provide one single interface.
  • Provider jar - Provide implementations in jars. You can even put several implementations in a jar. In a text file META-INF/services/my.package.MyInterface one lists implementing class(es).
  • Application - In the application the implementing jar should not be needed for compilation: in maven scope runtime.

The service discovery happens with a ServiceLoader<T>:

public static void main(String[] args) {
    ServiceLoader<MyInterface> loader = ServiceLoader.load(MyInterface.class);
    for (MyInterface api : loader) {
        api. ...
    }
    // Or take the first implementation:
    MyInterface api = loader.iterator().next();
}

You could provide a class in the API jar with a static function for that discovery mechanism.

Advantages:

  • Separation
  • Several implementations possible
  • Selection of implementation can be done dynamically

Example of jars

  • xxx-api.jar
    • my/package/MyInterface.class
  • xxx-first-impl.jar
    • META-INF/services/my.package.MyInterface
      • my.package.impl.MyImpl1
    • my/package/impl/MyImpl1.class
      • public class MyImpl1 implements MyInterface { ... }
  • myapp1.jar
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

If you'd like to start with theory. Please read about Dependency inversion principle.

In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are inverted (i.e. reversed), thus rendering high-level modules independent of the low-level module implementation details.

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

The principle inverts the way some people may think about object-oriented design, dictating that both high- and low-level objects must depend on the same abstraction.

Dependency Injection Library

As for specific implementations, you have many in Java. Specifically for the Dependency Injection approach. Spring Framework obviously comes to mind. But you can also look at Java EE Context and Dependency Injection.

Interface Injection

You can also...

  1. Load the Jars manually : How should I load Jars dynamically at runtime?
  2. Use Interface Injection : Spring interface injection example ( This title says Spring, but the answers show no Spring is needed for Interface Injection )
Community
  • 1
  • 1
kervin
  • 11,672
  • 5
  • 42
  • 59
  • @kevin I am pretty familiar with the concept, but in the examples you provided the client is bind in compile time to the impl, but in my case the client and the factory don't know about the impl till run time. It is some thing like slf4j approach with its impls. – A.v Jun 10 '15 at 13:04
  • @Ali.Valizadeh In neither case does the client nor the implementation need to know of each other. As the Wikipedia link explains, they would need a shared Interface or Base class. E.g. "IJob" or "JobBase" class. But that can be very generic. – kervin Jun 10 '15 at 13:13
  • But something should provide the instance of that Interface for the client.(in this case a factory) Is it wrong? – A.v Jun 10 '15 at 13:46
  • As wiki explains **"All variable instantiation requires the implementation of a Creational pattern as the Factory Method or the Factory pattern, or the more complex use of a Dependency Injection framework."** So the factory is depend on implementation in compile time. The problem is I want to have this dependency just in run time. – A.v Jun 10 '15 at 13:51
  • @Ali.Valizadeh Your "Creational Pattern" is your Interface. You can inject an "Object" using these methods. But what's the point in that? I.e. There must be an interface in the client letting it know how to use the injected object. That has nothing to do with the Factory. If you create an "Object Factory" then you wouldn't need an interface. But of course that wouldn't be very useful. – kervin Jun 10 '15 at 13:57
  • That all the point. I have an api which i give it to some consumers. They present their own implementation. the point is I want to give them a factory object which find all implementation of my api in their classpath and let my factory present theirs impl. I don't know any better way to explain it. – A.v Jun 10 '15 at 14:01
  • And this answer would do exactly that. What you are missing I think is the fact that your consumers ( providers ) will have to share an interface ( i.e. your API ). There is no "shared nothing" approach to this. That's the entire purpose of an API. – kervin Jun 10 '15 at 14:18