Reputation: 53149
In C++ or C, you can do things like this:
#ifdef WINAPI
public void showWindow(int cmdShow);
#endif
But in java, how can I define methods, that will only be compiled when user has enabled a library? I'm making a cross-platform application that uses certain native features which were not yet abstracted by JVM.
Also, I often make constructors that allow making my class from an object coming from some library. In that case, once the constructor is there, it force user to have that library. Instead, I'd like it to be only enabled when user has that library.
Upvotes: 4
Views: 1125
Reputation: 9816
Java does not have the concept of macros or templates. Instead it has reflection and generics. In your case, you would use reflection. The idea is to code to interfaces and then at runtime figure out which implementation to use. If no suitable/custom implementation is found you need to fall back to some default (possibly a no-op implementation if you want nothing to happen by default).
The best way to support such architecture is to provide an entry point to your hierarchy of interfaces, i.e., a factory. The entry point will then provide to all clients the implementations they need. The entry point can use reflection to figure out which implementation you want, e.g.,
public final class LibraryManager {
public static LibraryInterface find(String url) { ... }
}
The LibraryManager
above figures out via reflection which implementation of LibraryInterface
you want to obtain at runtime. The url
can be simply the fully qualified class name of the required implementation of LibraryInterface
, e.g., com.my.pack.MyLibraryInterfaceImpl
.
To understand this in practice, take a look at JDBC's DriverManager
: you get an implementation of Connection
by providing the DriverManager.getConnection
method with a jdbc URL. Behind the curtains, DriverManager
uses reflection to find the right driver and returns the implementation needed. If the driver library for the given URL is not available you will get an exception.
In your case, the only modification you need to make to that pattern is to provide some default implementation if no library is specified. If the implementations rely on 3rd party libraries you are going to need to write appropriate adapters that use these, etc.
Note that in many cases you would actually return a factory to your library implementation so you can create many instances of the library objects. This works exactly the same way as above except you return some LibraryFactoryInterface
instead.
Finally, if you use some kind of IoC or DI framework like Spring, you can define your implementation factory at configuration time to be injected in your application. A typical example and an alternative to DriverManager
is DataSource
. It's very common in a Spring application to define your DataSource
s in the configuration file. Spring will take care of wiring the DataSource
into the objects that need to connect to the database.
Upvotes: 4