0

コードにイベント リスナーのリストがあります。

private List<EventListener> listeners = new ArrayList<EventListener>();
listeners.add(new EventListener() {
    @Override
    public void someEvent(String arg1, MyClass arg2) {
        // ...
    }

    @Override
    public void someOtherEvent(AnotherClass arg1, int arg2) {
        // ...
    }
}

現在、for ループを使用してリスナーを呼び出しています。

for (EventListener listener : listeners) {
    listener.someEvent("Hello world", (MyClass) myObject);
}

次のように、単一のメソッドを使用して呼び出したいと思います。

fireEvent("someEvent", "Hello world", (MyClass) myObject);

または、イベント引数の配列または何か。

これを行う 1 つの方法は、ある種のイベント オブジェクトを作成することですが、面倒なので特にやりたくありません (ここで間違っているかどうか誰か教えてください。私は Java の経験がありません)。上記のような fireEvent を作成する方法はありますか? それが役立つ場合、EventListenerはインターフェースです。

4

1 に答える 1

1

理論的には、Java リフレクションを使用してこれを行うことができます。

public void fireEvent(String name, Object... args) {
    Method method = null;
    // 1. find method
    for (Method m : EventListener.class.getMethods()) {
        if (m.getName().equals(name)) {
            method = m;
            break;
        }
    }

    if (method == null) {
        throw new IllegalArgumentException("Unknown event method: " + name);
    }

    // 2. call method on all listeners
    for (EventListener l : listeners) {
        try {
            method.invoke(l, args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

(これは、オーバーロードされたイベント メソッドなどのすべての事象をカバーしていない簡単なバージョンであることに注意してください。)

しかし、そうしないことを強くお勧めします。醜くて読みにくいだけでなく、プログラムがタイプセーフではなくなります! 間違った名前Stringや間違った数またはタイプのパラメーターを使用すると、コンパイラーは気付かないでしょうが、プログラムは実行時に壊れます!

したがってfireXXXEvent、リスナーのすべてのイベント ハンドラー メソッドに対して 1 つの保護されたメソッドを使用することをお勧めします (単純な for ループを使用)。あなたの場合、これは次のようになります。

protected void fireSomeEvent(String arg1, MyClass arg2);
protected void fireSomeOtherEvent(AnotherClass arg1, int arg2);

もちろん、イベント オブジェクトを導入することもできます (サブクラス化による可能性がありますjava.util.EventObject)。ただし、これによってリスナーのメソッドの数が必ずしも減るとは限りません (ただし、取得したイベントの種類によっては減る可能性があります)。

JavaFX のように、イベント タイプ オブジェクトと汎用イベント オブジェクトを含む汎用イベント ハンドラーを使用するなど、より手の込んだ戦略がいくつかありますが、Java にあまり詳しくない場合は、これはお勧めできません。

補足: リスナーを保存するために a を使用するか、イベントを発生させるときにCopyOnWriteArrayListのコピーを反復処理します。そうしないと、リスナーがリスナー リストから自身を削除しようとした場合に a を取得する可能性があります。listenersConcurrentModificationException

于 2013-11-13T23:35:18.413 に答える