0

假设我有一个制造调度系统,它由四个部分组成:

  • 有些工厂可以生产某种类型的产品并知道他们是否忙:

    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 中的键丢失,...)并且非常非最优(可以迭代 entryset 而不是 keyset,...)

现在的问题:

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

即使在这种情况下,应该清楚这没关系......

我想我可以为每个调用的 Product 添加一个“buildMe()”函数factory.buildProduct(this),但我很难相信这应该是我最优雅的解决方案。

有任何想法吗?

编辑:

Product 和 Factory 实现的简单示例:

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
    }
}
4

3 回答 3

0

你的代码很奇怪。
您的问题是您将 A 传递Product<?>给一个期望 aProductType实际上是的方法T
我也不知道是什么Product,因为你没有在 OP 中提到它的定义。
你需要通过aProduct<?>才能工作。我不知道你会从哪里得到它,因为我不明白你想用你的代码做什么

于 2012-11-29T21:16:58.800 回答
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());
}
于 2012-11-29T21:18:33.090 回答
0

知道了!感谢 Meriton 回答了这个版本的问题:

如何用编译时泛型验证替换运行时 instanceof 检查

我需要通过product.getFactory().buildProduct(product)在单独的通用函数中执行此操作来逐步通过 -part 编译器。以下是我需要对代码进行的更改以使其正常工作(真是一团糟):

  • 更具体地了解 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")上的注释,而不是某些 Product 对象。addNextOrder()因为我只在这个队列上调用“add”,在编译和类型擦除之后,它会将所有元素简单地存储为对象,这不应该导致任何运行时转换异常。(如有错误请指正!)

于 2012-11-30T01:16:28.267 回答