mdd-sbo
mdd-sbo

Reputation: 633

Generic and the Factory Pattern

Let's say I have an abstract class, Element, and an interface Model.

Element has a method setModel(Model model).

Say Element instances reference a single Model implementation instance commonly, for things like deserializing from ReST, serializing to SQL tuples, etc.

Every Element subclass is associate with one specific Model, but any Model might be associated with any number of Element classes, so something like this:

public abstract class Element<M extends Model> {
  private M mModel;
  public void setModel(M model) {
    mModel = model;
  }
}

And

public interface Model {
  // .. stuff
}

Now let's say I want to create a factory that produces Elements from Models. Given that a Model might be connected to a number of Element classes, we can expect that we need to provide the specific class. So something like this in the end result:

ElementSubclass e = new ElementFactory(ElementSubclass.class).from(someModelInstance);

or....

ElementFactory factory = new ElementFactory(ElementSubclass.class);
for(Model model : listOfModels) {
  ElementSubClass element = factory.from(model);
  listOfElementSubClassInstances.add(element);
}

Getting there has been less straightforward than I'd have thought. I've ended up with something like:

public class ElementFactory {

  private Class<? extends Element> mElementClass;

  public <E extends Element> ContentModelElementFactory(Class<E> elementClass) {
    mElementClass = elementClass;
  }

  public <E extends Element> E from(Model model) {
    try {
      Element e = mElementClass.newInstance();
      e.setModel(model);
      return (E) e;
    } catch (Exception ex) {
      //
    } 
    return null;
  }

}

Seems a little shaky, and lint complains about both the call to setModel and the cast on the line beneath.

I'd considered something like new ElementFactory<ElementSubclass>(ElementSubclass.class) but that reads poorly - we already designated element subclass once, it seems heavy-handed to do so as both a type and an argument.

There's also the static version, like public static <E extends Element> E create(Class<E> clazz, Model model) but obviously it's not a reusable as a true factory and seems a little less graceful.

Is there a better way to express this idea?

Upvotes: 1

Views: 101

Answers (1)

lexicore
lexicore

Reputation: 43661

Since generic types are erased, you have to pass your ElementSubclass to the factory, no way around that.

If you're irritated by new ElementFactory<ElementSubclass>(ElementSubclass.class) then write a generic static method like public static <E extends Element> ElementFactory<E> of(Class<E> elementClass). This will give you code like:

ElementFactory<ElementSubclass> factory = ElementFactory.of(ElementSubclass.class);

Which feels somewhat better.

Upvotes: 1

Related Questions