假设我有一个制造调度系统,它由四个部分组成:
-
有些工厂可以生产某种类型的产品,并知道他们是否很忙:
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)
的Product添加一个"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
}
}
您的代码很奇怪
您的问题是将Product<?>
传递给一个方法,该方法期望ProductType
实际上是T
我也不知道Product
是什么,因为你在OP中没有提到它的定义。
你需要传递一个Product<?>
才能工作。我不知道你会在哪里得到它,因为我不明白你试图用你的代码做什么
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());
}
明白了!感谢meritn,他回答了这个版本的问题:
如何用编译时泛型验证替换运行时检查实例
我需要在一个单独的泛型函数中逐步完成product.getFactory().buildProduct(product)
部分。以下是我需要对代码进行的更改,以使其正常工作(真是一团糟):
-
更具体地介绍订单系统:
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循环中。
还要注意,addNextOrder()
函数上的@SuppressWarnings("unchecked")
注释是队列的类型转换所必需的,而不是某些Product对象。由于我只在此队列上调用"add",在编译和类型擦除后,该队列将所有元素简单地存储为对象,因此这不应导致任何运行时强制转换异常。(如果这是错误的,请纠正我!)