我有相应的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,但我不知道该怎么做。 我怎么解决这个问题?
我习惯抽象工厂,但我从未将它用于泛型。我在解释模式时是否犯了一些错误?
答案 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
,因此可以合法地抑制未经检查的警告。