views:

113

answers:

4

I am writing an application that will ship in several different versions (initially around 10 variations of the code base will exist, and will need to be maintained). Of course, 98% or so of the code will be the same amongst the different systems, and it makes sense to keep the code base intact.

My question is - what would be the preferred way to do this? If I for instance have a class (MyClass) that is different in some versions (MyClassDifferent), and that class is referenced at a couple of places. I would like for that reference to change depending on what version of the application I am compiling, rather than having to split all the classes referring to MyClassDifferent too. Preprocessor macros would be nice, but they bloat the code and afaik there are only proof of concept implementations available?

I am considering something like a factory-pattern, coupled with a configuration file for each application. Does anyone have any tips or pointers?

+4  A: 

You are on the right track: Factory patterns, configuration etc.

You could also put the system specific features in separate jar files and then you would only need to include the appropriate jar alongside your core jar file.

Fortyrunner
+2  A: 

I'd second your factory approach and you should have a closer look at maven or ant (depending on what you are using). You can deploy the different configuration files that determine which classes are used based on parameters/profiles.

Preprocessor makros like C/C++ have are not available directly for java. Although maybe it's possible to emulate this via build scripts. But I'd not go down that road. My suggestion is stick with the factory approach.

Patrick Cornelissen
+2  A: 

fortunately you have several options

1) ServiceLoader (builtin in java6) put your API class like MyClass in a jar, the compile your application against this API. Then put a separate implementation of MyClass in a separate jar with /META-INF/services/com.foo.MyClass. . Then you can maintain several version of your application simply keeping a "distribution" of jars. Your "main" class is just a bunch of ServiceLoader calls

2) same architecture of 1) but replacing META-INF services with Spring or Guice config

3) OSGI

4) your solution

dfa
+1  A: 

Look up the AbstractFactory design pattern, "Dependency Injection", and "Inversion of Control". Martin Fowler writes about these here.

Briefly, you ship JAR files with all the needed components. For each service point that can be customized, you define an Interface for the service. Then you write one or more implementations of that Interface. To create a service object, you ask an AbstractFactory for it, eg:

AbstractFactory factory = new AbstractFactory();
...
ServiceXYZ s = factory.newServiceXYZ();
s.doThis();
s.doThat();

Inside your AbstractFactory you construct the appropriate ServiceXYZ object using the Java reflection method Class.classForName(), and SomeClassObject.newInstance(). (Doing it this way means you don't have to have the ServiceXYZ class in the jar files unless it makes sense. You can also build the objects normally.)

The actual class names are read in from a properties file unique to each site.

You can roll your own solution easily enough, or use a framework like Spring, Guice, or Pico.

Jim Ferrans