私は現在、単純なイベントリスナーライブラリを作成しています。
これがリスナーのための私のインターフェースです:
public interface Listener<T> {
// Event is a very simple type which holds a variable T data.
public boolean run(Event<T> e);
}
私のクラスListenable
はすべてListener
のをHashMapに記録します:
protected HashMap<String, ArrayList<Listener<?>>> listeners;
Listenable
インスタンスに複数のイベントタイプを持たせたいので、ここではワイルドカードを使用しています。
問題のある部分は私のListenable::dispatchEvent()
方法にあります:
public boolean dispatchEvent(Event<?> evt) {
ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
if (evtListeners == null) {
return true;
}
for (Listener<?> lst : evtListeners) {
// vvv--- error
if (!lst.run(evt) || evt.shouldStopPropagation()) {
return false;
}
}
return true;
}
エラーメッセージは次のとおりです。
タイプListenerのメソッドrun(Event)は、引数(Event)には適用できません。
私は「解決策」を見つけました(コンパイラにエラーを隠すという意味で):
for (Listener lst : evtListeners) {
if (!lst.run(evt) || evt.shouldStopPropagation()) {
return false;
}
}
この場合、コンパイラは2つの警告しか生成しませんが、この手法は非常に貧弱であることをここで読みました。
私はそれをこのコードで動作させました
public <T> boolean dispatchEvent(Event<T> evt) {
ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
if (evtListeners == null) {
return true;
}
for (int i = 0; i < evtListeners.size(); i++) {
@SuppressWarnings("unchecked")
Listener<T> lst = (Listener<T>) evtListeners.get(i);
if (!lst.run(evt) || evt.shouldStopPropagation()) {
return false;
}
}
return true;
}
しかし、これがクリーンなコードだとは思えませんね。私のライブラリのユーザーは、同じイベントタイプ(evt.getType()
)のタイプを混在させないことを前提としています。
何か提案をいただければ幸いです。