タイプセーフなjava.util.Observableを書いてみた
オブザーバーの仕組みはjava.util.Observableを使うとさくっと作れますが、パラメータで渡されるイベント?などがObject型になっていてちょい使いにくい。そこで、イベントの型をパラメータで指定できるようにするラッパーを書いてみました。
/** * タイプセーフな{@link java.util.Observable} */ public class Observable<E, T extends Observable<E, T>> extends java.util.Observable { public void notifyObserversExt( E event ) { notifyObservers( event ); } public void addObserver ( Observer<E, T> o ) { addObserver( new Bridge<E,T>( o ) ); } public void deleteObserver ( Observer<E, T> o ) { deleteObserver( new Bridge<E,T>( o ) ); } public static interface Observer<E, T extends Observable<E, T>>{ void update( T target, E event ); } private static final class Bridge<E, T extends Observable<E, T>> implements java.util.Observer { private final Observer<E, T> org; private Bridge( Observer<E, T> org) { this.org = org; } public void update ( java.util.Observable o, Object arg ) { org.update( (T) o, (E) arg ); } @Override public boolean equals( Object obj ) { if ( obj == null ) { return false; } if ( obj instanceof Bridge ) { return org.equals( ((Bridge<E, T>) obj).org ); } return false; } @Override public int hashCode() { return org.hashCode(); } } }
利用例。以下のような感じでイベントとか監視されるクラスを作って、
/**イベント*/ static final class Event {} /**監視されるクラス*/ static final class TestObservable extends Observable<Event, TestObservable>{ @Override public void setChanged() { super.setChanged(); } } /***監視クラス1*/ static final class TestObserver1 implements Observer<Event, TestObservable> { public void update ( TestObservable target, Event event ) { System.out.println( "1 : " + String.valueOf( event != null ? event.hashCode() : "null" ) ); } } /***監視クラス1*/ static final class TestObserver2 implements Observer<Event, TestObservable> { public void update ( TestObservable target, Event event ) { System.out.println( "2 : " + String.valueOf( event != null ? event.hashCode() : "null" ) ); } }
↓こんな感じで呼び出せます。
TestObservable test = new TestObservable(); TestObserver1 o1 = new TestObserver1(); TestObserver2 o2 = new TestObserver2(); test.addObserver( o1 ); test.addObserver( o2 ); test.setChanged(); test.notifyObserversExt( new Event() ); test.setChanged(); test.notifyObservers(); test.deleteObserver( o1 ); test.setChanged(); test.notifyObserversExt( new Event() ); test.setChanged(); test.notifyObservers();
実行結果です。
2 : 13141056 1 : 13141056 2 : null 1 : null 2 : 6460284 2 : null
それにしても、「setChanged()」しないと通知がされないのが鬱陶しいな。こんな仕様だっけ?(←実はあまり使ったことがなかったり。)