たとえば、次の 4 つの部分で構成される製造スケジューリング システムがあるとします。
特定のタイプの製品を製造でき、忙しいかどうかを知ることができる工場があります。
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 の欠落のキーとして factory が存在するかどうかを確認するなど) があり、非常に最適ではありません (keyset ではなく entryset を反復処理する可能性があるなど)。
今質問:
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);
}
}
この場合、これで問題ないことは明らかなはずですが...
を呼び出すすべての製品に「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
}
}