Search code examples
javadesign-patternsgenericsinterfaceabstract-factory

AbstractFactory with generic types in Java: a design problem


I have the following 2 interfaces accordingly to abstract factory pattern:

public interface GenericObjectInterface<T extends Number>{
    public T getResult();
}
public interface AbstractFactoryInterface{
    public <T extends Number> GenericObjectInterface<T> createGenericObject();
}

I have an abstract class implementing GenericObject, but it's still unaware of the concrete type (it does only generic operations on Number):

public abstract class GenericAbstractClass<T extends Number> implements GenericObjectInterface<T>{   } 

Then I have a series of concrete class extending that perform generic parameter substitution:

public class IntegerObject extends GenericAbstractClass<Integer>{
     public Integer getResult(){}
}
....

Now, from inside an implementation of the factory I build the concrete type, that's implementing GenericObjectInterface but has lost it's generic parameter:

public class ConcreteFactory{
    public <T extends Number> GenericObjectInterface<T> greateGenericObject(Class<T> c){
         if (c.class.isInstance(Integer.class)){
             IntegerObject obj = new IntegerObject();
             //I would like to return obj
             GenericObjectInterface<T> a = new IntegerObject(); //errror
             GenericAbstractClass<T> a = new IntegerObject(); //errror

             return a;
          }else if (c.class.isInstance(Double.class)){
          }
    }
}

I would like to return obj that implements GenericObjectInterface but I don't know how can I do it. how can I solve this?

I'm used to abstract factory but I've never used it with generics. Am I doing some mistakes in interpreting the pattern?


Solution

  • If your method returns an IntegerObject why don't you just return GenericObjectInterface<Integer>? You already know the parameter type.

    In that case, just add a generic parameter to AbstractFactoryInterface, too:

    public interface AbstractFactoryInterface<T extends Number> { ... }
    
    public class ConcreteFactory implements AbstractFactoryInterface<Integer> { ... }
    

    In your implementation the type of T would be inferred from the assignment, and thus you could do this:

     GenericObjectInterface<Double> g = new ConcreteFactory().greateGenericObject();
    

    In that case T would be Double but you'd use Integer internally, resulting in this:

    GenericObjectInterface<Double> a = new IntegerCell(); 
    

    Since the compiler can't ensure that T will always be of type Integer it won't allow you to do that assignment.