0

たとえば、次の 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
    }
}
4

3 に答える 3

0

とった!このバージョンの質問に答えたメリットンに感謝します。

実行時の 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")、関数の注釈は、addNextOrder()製品オブジェクトではなく、キューの型キャストに必要であることに注意してください。コンパイルと型消去の後、すべての要素を単純にオブジェクトとして格納するこのキューで「追加」を呼び出すだけなので、実行時のキャスト例外が発生することはありません。(これが間違っている場合は修正してください!)

于 2012-11-30T01:16:28.267 に答える
0

あなたのコードは奇妙です。
あなたの問題は、実際にProduct<?>ある a を期待するメソッドに A を渡していることです。また、OPでその定義について言及していないため、何が 何であるかわかりません。 動作するには a を渡す必要があります。コードで何をしようとしているのか理解できないため、どこで入手できるかわかりませんProductTypeT
Product
Product<?>

于 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 に答える