1

私は、パラメーター化されたイベント用の単純なイベント システムを作成しています。これは、そのクラスをパラメーターとして持つMapクラスからハンドラーの s までを使用します。Set私の理解では、パラメーターの制限を介してキーと値の型の間の関係を定義することはできず、セットから要素を引き出す未チェックのキャスト警告が表示されます。

これが私が現在持っているものです:

public class Manager {
    private class Event<T> {
        // getSubject(), etc.
    }

    private interface Handler<T> {
        public T handleEvent(Event<T> event, T subject);
    }

    private final Map<Class<?>, Set<Handler<?>>> handlers = new HashMap<Class<?>, Set<Handler<?>>>();

    public <T> void post(final Event<T> event, final T subject) {
        final Class<?> type = subject.getClass();

        if (this.handlers.containsKey(type)) {
            for (Handler<?> handler : this.handlers.get(type)) {
                // unchecked cast
                ((Handler<T>) handler).handleEvent(event, subject);
            }
        }
    }

    public <T> void register(final Class<T> type, final Handler<T> handler) {
        if (!this.handlers.containsKey(type)) {
            this.handlers.put(type, new HashSet<Handler<?>>());
        }

        this.handlers.get(type).add(handler);
    }
}

このチェックされていないキャストを回避することは可能ですか? おそらく私の設計に欠陥がありますか?

こことGoogleでかなりの時間を費やしましたが、この取り決めを完全にカバーするものを見つけることができませんでした.

4

3 に答える 3

1

イベント クラス自体が階層を形成している場合は、Visitor パターンを使用してキャストを回避できます。Java では非常に面倒ですが、キャストは必要ありません。

于 2013-10-09T17:38:20.070 に答える
1

@SuppressWarnings("unchecked")残念ながら、この状況では他に何もできません。

Class<A>マップ宣言には、 aを aに関連付けるのを妨げるものは何もないSet<Handler<B>>ため、コンパイラは、これが事実であるかどうかを判断できない可能性があります。そして悲しいことに、 の実装にそのような制約を課す方法はありませんjava.util.Map

この強制を可能にする独自のデータ構造を実装する場合 ( のようなメソッドを提供する場合Handler<T> getHandler(Class<T> type)、そのデータ構造にチェックされていないキャストを埋め込むだけで、クライアント コードをきれいに保つことができます。

補足として、MapインターフェースはObjectなどのパラメーターとして を想定しているためget()containsKey()一般的なものはすべて失われます (キーのジェネリック型を対応する値の 1 つに関連付けることができたとしても、これは単に不可能です)。 )。

于 2013-10-09T19:23:01.813 に答える
0

私のコード構成は少し異なります。ブロードキャスター用のコードは、マネージャーに相当しますが、post() のコードでは次のようにします

for (Handler<T> handler : this.handlers.get(type)) {
   do stuff ...
}

<T>イベント引数は T によってパラメーター化されるため、 を Handler に追加できます。しかし、私は推測と大失敗、YMMVによって多くの派手なジェネリックのものをやっています... :-)

ps register() メソッドを同期する必要があります。

于 2013-10-09T17:43:09.213 に答える