tags:

views:

91

answers:

3

I am reading a Stream, which provides an identifier (a simple int). Depending on the int different data follows, which i need to turn into objects. So far i created classes for each object type, and each class provides a read(InputStream input)-method which reads whatever data there is to be read for that kind of object (all object classes inherit from a common base class).
However, there are numerous id's and thus numerous classes. What is the most elegant way to determine and create the instance of the class? The most naive approach i tried first was to have a switch-case block to create the instances, but i find that it clutters the code (unreasonably). It also forces me to have every class available at compile time.
Second try was to create a map that maps each int to a class and use newInstance() to create the objects. There is still the problem that i need to initialize the map, which still requires that i have every class available at compile time. It more or less just moved the clutter from one place to another.
Removing the compile time dependencies is not required, it would just be a bonus if possible. The main goal is to avoid the boilerplate code.

Constraints: I don't want to add a library to solve this. Reflection is fine with me.

+1  A: 

I think your map solution sounds fine, but move the initial map setup out of of the Java code and into a config file. (Class.forName will help here)

mlk
+5  A: 

An alternative approach is to still use a Map but essentially use late-binding, if that's preferable. You could even store the config in a properties file like:

1=java.lang.String
2=my.class.Something
...etc...

You then do something like this:

Map<Integer,ObjectFactory> loader = ... // load from properties; fairly trivial

assuming:

public class ObjectFactory {
  private Final String className;
  private transient Class clazz;

  public ObjectFactory(String className) {
    this.className = className;
  }

  public Object createInstance() {
    try {
      if (clazz == null) {
        clazz = Class.forName(className);
      }
      return clazz.newInstance();
    } catch (Exception e) {
      throw new IllegalStateExxception("Could not crate " + className, e);
    }
  }
}
cletus
There are many variations on the factory pattern with dynamic type support you can use, but this answer should be enough to get the OP on his way.
hbunny
+1  A: 

You could have a registry with prototypes.

A prototype of each class you want to be able to create (at a point in time) could be added to your registry object at runtime, these prototypes would each have their own unique integer id.

When you want an object of id x, you just ask of your registry object to clone and return the prototype which id is x. (or null if no such prototype is currently registered).

Internally the registry could be a (hash)map for quick retrieval, but it could just as easily be a list of prototypes (Do make sure of course that all prototypes implement a common interface the registry can work with). Best thing is, no need for reflection!

NomeN