Search code examples
javafactory-patterngeneric-constraints

Java factory pattern using generic constraints


I have

public class  MyFactory()
{
   public static <T> T getItem(Element element, Class<T> clazz)
   {
         T item = null;
         if (clazz == IFoo.class)
         {
              item =  (T) new Foo();
         }
         else if (clazz == IBar.class)
         {
              item =  (T) new Bar();
         }
         ...

        assert item instanceof IParsable;
        (IParsable(foo)).parse(element)

       return item;
   }

}

and then I call it like this

IFoo parsedFoo = MyFactory.getItem(someElement, IFoo.class);

Here the concrete classes implement IParsable . Would I be able to remove the runtime assert check and put a compile time check to see if 'IParsable' and call parse?

Also I was wondering if there is a way to enforce IFoo<-->Foo implements relationship at compile time in getItem() method and remove the typecasting (T) ?

EDIT: I thought I would give an outline for IFoo and Foo

public interface IFoo
{
    String getFooName();
    int getFooId();
    ....
}


class Foo implements IFoo, IParsable
{
      ...
}

EDIT2:

I just thought of a refactoring like this, now the only thing that's not a compile time check is the relation between interface and implementation.

  public static <U extends IParsable, T> T getItem(Element element, Class<T> clazz)
   {
         U item = null;
         if (clazz == IFoo.class)
         {
              item =  (U) new Foo();
         }
         else if (clazz == IBar.class)
         {
              item =  (U) new Bar();
         }
         ...

       item.parse(element)

       return (T) item;
   }

Solution

  • Maybe something like this:

    public static <T> T getItem(Element element, Class<T> clazz) {
        IParsable item = null;
        if (clazz == IFoo.class) {
            item = new Foo();
        } else if (clazz == IBar.class) {
            item = new Bar();
        }
        item.parse();
        return (T) item;
    }
    

    The fact that Foo is an IParsable is checked at compile time. The other cast (to (T)) is still a runtime exercise - but it was also the case in your example.