假设我有一个制造调度系统,它由四部分组成:
有些工厂可以生产某种类型的产品并知道他们是否忙碌:
interface Factory<ProductType> {
void buildProduct(ProductType product);
boolean isBusy();
}
有一套不同的产品,除其他外,知道它们在哪个工厂建造:
interface Product<ActualProductType extends Product<ActualProductType>> {
Factory<ActualProductType> getFactory();
}
然后有一个订购系统可以生成对要构建的产品的请求:
interface OrderSystem {
Product<?> getNextProduct();
}
最后,有一个调度员抓住订单并维护每个工厂的工作队列:
class Dispatcher {
Map<Factory<?>, Queue<Product<?>>> workQueues
= new HashMap<Factory<?>, Queue<Product<?>>>();
public void addNextOrder(OrderSystem orderSystem) {
Product<?> nextProduct = orderSystem.getNextProduct();
workQueues.get(nextProduct.getFactory()).add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
factory.buildProduct(workQueues.get(factory).poll());
}
}
免责声明:此代码仅仅是一个示例,并且有几个错误(检查工厂是否存在缺少workQueues中的键,...)并且非常不优化(可以迭代入口集而不是键集,。 ..)
现在的问题是:
Dispatcher中的最后一行(factory.buildProduct(workqueues.get(factory).poll());
)抛出此编译错误:
The method buildProduct(capture#5-of ?) in the type Factory<capture#5-of ?> is not applicable for the arguments (Product<capture#7-of ?>)
我一直在努力解决如何以类型安全的方式解决这个问题,但我的仿制技能让我失败了......
例如,将其更改为以下内容也无济于事:
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy()) {
Product<?> product = workQueues.get(factory).poll();
product.getFactory().buildProduct(product);
}
}
即使在这种情况下,应该很清楚这是可以的......
我想我可以为每个调用factory.buildProduct(this)
的产品添加“buildMe()”函数,但我很难相信这应该是我最优雅的解决方案。
有什么想法吗?
修改
产品和工厂实施的快速示例:
class Widget implements Product<Widget> {
public String color;
@Override
public Factory<Widget> getFactory() {
return WidgetFactory.INSTANCE;
}
}
class WidgetFactory implements Factory<Widget> {
static final INSTANCE = new WidgetFactory();
@Override
public void buildProduct(Widget product) {
// Build the widget of the given color (product.color)
}
@Override
public boolean isBusy() {
return false; // It's really quick to make this widget
}
}
答案 0 :(得分:0)
你的代码很奇怪
您的问题是,您将A Product<?>
传递给期望ProductType
实际上为T
的方法。
另外我不知道Product
是什么,因为你没有在OP中提及它的定义
您需要传递Product<?>
才能工作。我不知道你会在哪里得到它,因为我无法理解你想用你的代码做什么
答案 1 :(得分:0)
Map<Factory<?>, Queue<Product<?>>> workQueues = new HashMap<Factory<?>, Queue<Product<?>>>();
// factory has the type "Factory of ?"
for (Factory<?> factory: workqueues.keySet())
// the queue is of type "Queue of Product of ?"
Queue<Product<?>> q = workqueues.get(factory);
// thus you put a "Product of ?" into a method that expects a "?"
// the compiler can't do anything with that.
factory.buildProduct(q.poll());
}
答案 2 :(得分:0)
知道了!感谢meriton回答了这个问题的版本:
How to replace run-time instanceof check with compile-time generics validation
我需要通过product.getFactory().buildProduct(product)
- 在一个单独的泛型函数中执行此操作来完成编译器。以下是我需要对代码进行的更改以使其工作(多么糟糕):
更具体地说明OrderSystem:
interface OrderSystem {
<ProductType extends Product<ProductType>> ProductType getNextProduct();
}
定义我自己的,更强类型的队列来保存产品:
@SuppressWarnings("serial")
class MyQueue<T extends Product<T>> extends LinkedList<T> {};
最后,将Dispatcher更改为此野兽:
class Dispatcher {
Map<Factory<?>, MyQueue<?>> workQueues = new HashMap<Factory<?>, MyQueue<?>>();
@SuppressWarnings("unchecked")
public <ProductType extends Product<ProductType>> void addNextOrder(OrderSystem orderSystem) {
ProductType nextProduct = orderSystem.getNextProduct();
MyQueue<ProductType> myQueue = (MyQueue<ProductType>) workQueues.get(nextProduct.getFactory());
myQueue.add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
buildProduct(workQueues.get(factory).poll());
}
public <ProductType extends Product<ProductType>> void buildProduct(ProductType product) {
product.getFactory().buildProduct(product);
}
}
注意所有通用函数,尤其是最后一个函数。还要注意,我不能像在原始问题中那样将此函数内联到我的for循环中。
另请注意,队列的类型转换需要@SuppressWarnings("unchecked")
函数上的addNextOrder()
注释,而不是某些Product对象。因为我只在这个队列上调用“add”,在编译和类型擦除之后,将所有元素简单地存储为对象,这不应该导致任何运行时转换异常。 (如果这是错的,请纠正我!)