読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

タイプセーフなjava.util.Observableを書いてみた

Java

オブザーバーの仕組みは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()」しないと通知がされないのが鬱陶しいな。こんな仕様だっけ?(←実はあまり使ったことがなかったり。)