AbstractFactory与Java中的泛型类型:一个设计问题

时间:2011-09-23 14:37:27

标签: java design-patterns generics interface abstract-factory

我有相应的2个接口来抽象工厂模式:

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

我有一个实现GenericObject的抽象类,但它仍然没有意识到具体类型(它只对Number进行泛型操作):

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

然后我有一系列具体的类扩展,执行泛型参数替换:

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

现在,从工厂的实现内部构建具体类型,即实现GenericObjectInterface,但已经丢失了它的通用参数:

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)){
          }
    }
}

我想返回实现GenericObjectInterface的obj,但我不知道该怎么做。 我怎么解决这个问题?

我习惯抽象工厂,但我从未将它用于泛型。我在解释模式时是否犯了一些错误?

4 个答案:

答案 0 :(得分:3)

如果您的方法返回IntegerObject,为什么不返回GenericObjectInterface<Integer>?您已经知道参数类型。

在这种情况下,只需将通用参数添加到AbstractFactoryInterface

public interface AbstractFactoryInterface<T extends Number> { ... }

public class ConcreteFactory implements AbstractFactoryInterface<Integer> { ... }

在您的实现中,T的类型将从赋值中推断出来,因此您可以这样做:

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

在这种情况下,T将是Double,但您在内部使用Integer,结果如下:

GenericObjectInterface<Double> a = new IntegerCell(); 

由于编译器无法确保T始终为Integer类型,因此不允许您执行该分配。

答案 1 :(得分:1)

抽象工厂的特点是工厂方法返回接口或抽象类引用而不是具体引用。它扩展到类型参数。

以这种方式思考:你能做到这一点吗?

public class ConcreteListFactory {
    public <T> List<T> createList() {
        return new ArrayList<String>();
    }
}

如果来电者想要List<Integer>

,该怎么办?

如果您希望工厂返回一个通用类型,则应该让您的具体类接受type参数。否则,您的工厂方法将返回GenericObjectInterface<Integer>

或者,您可以让您的方法接受类型标记(Integer.class)。例如:

public <T extends Number> GenericObjectInterface<T> createGenericObject(Class<T> clazz) {
    if ( clazz.equals(Integer.class) ) {
        return (GenericObjectInterface<T>) new IntegerObject();
    }
} 

这将导致未经检查的投射警告,但您可以向自己证明它是安全的,从而抑制警告或忽略警告。

答案 2 :(得分:1)

通常,工厂不是作为泛型实现的,因为你不能检查泛型的类型来确定要创建的对象的类型(你不能做T.getClass)这就是为什么@Mark的例子导致类到作为参数传递。

我认为,通常你会有多个混凝土工厂。每个您打算支持的数字类型一个。

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


class IntegerFactory implements AbstractFactoryInterface<Integer>...
class LongFactory implements AbstractFactoryInterface<Long>...

然后,您可以创建Map&lt; Class,AbstractFactoryInterface&gt; ...

Map<Class, AbstractFactoryInterface> myMap = ...;
myMap.put(Integer.class, new IntegerFactory());
myMap.put(Long.class, new LongFactory ());

答案 3 :(得分:1)

这里的铸造非常好。如果c==Integer.class,则T=Integer,将GOI<Object>投射到GOI<T>是绝对正确的。这是一个经过检查的演员,因为您在投票前已经检查了T=Integer,因此可以合法地抑制未经检查的警告。