ファイヤープロジェクト
総称クラスのオブザーバーパターンへの応用
2008-11-16T08:00+09:00   matsu
総称クラスによって,オブザーバーパターンの実装がちょっといい感じになる.
オブザーバーパターンは,GOFのデザインパターンの一つで,Observer(監視者)とObservable(披監視者)に分類される二種類のクラスで通知の仕組みを規定しましょうというものである. 実際には,Observableが自身が変更された際,Observerに申告する形(Observerのupdateメソッド呼び出し)となる. JDKにも1.0の頃からObserverのインタフェース
java.util.Observer
と,Observableの実装クラス
java.util.Observable
があり,Observableに,Observerの登録,削除,通知などの管理の実装がある. これらは以下のように使用することになると思う.
public class Hoge extends Observable {
  public void modify() {
    // 何か更新する
    ....

    // 更新をマーク
    setChanged();

    // Observerに通知
    notifyObservers();
  }
}

public class HogeObserver implements Observer {
  // hogeに更新があった場合,hogeオブジェクトから呼び出される.
  // updatedは更新されたObservable(Hogeオブジェクト).
  void 	update(Observable updated, Object arg) {
    // 更新時に呼び出すことにしているHogeのメソッド.
    // 引数はObservableなので,キャストする必要がある.
    (Hoge)updated.hogeMethod();
  }
}

public class HogeUser {
  public void modifyHoge() {
    Hoge hoge = new Hoge();
    // ObservableにObserverを登録
    hoge.addObserver(new HogeObserver());
    // Observerを更新
    hoge.modify();
  }
}
問題は2点.
  • HogeはObserverを拡張すると他のクラスを拡張できない
  • 実際のObserverは,観察する対象を知っているはずなので,上の枠組ではObserverは必ずキャストしなければならないのがなんだか許せない.
前者は委譲すればすむだけの話しにも思える. 例えば
public class Hoge extends GenericHoge {
  private Observable observable = new Observable();

  void addObserver(Observer o) {
    observable.addObserver(o);
  }
...
}
後者は,今なら総称型を使用して回避できそうな気がする.
前節の問題点を解決するために,委譲と総称型を使用してオブザーバーパターンを実装してみた. まずクラス図.
継承ではなく委譲で実装するため,MyObservableとMyObserverは直接結ばず,ObserverHelperにて関連付けてみた. そしてシーケンス図.
まず,MyObserverインタフェースは,実装時にupdateメソッドにて具体的なクラスを引数に取れるよう,総称型を使用した.
これを実装するのは,HogeOserver.
このクラスではimplementsで指定する際に,監視対象であるMyObservable実装クラスHogeを指定している.
public class HogeObserver implements MyObserver<Hoge> {
これにより,updateメソッドでは,第一引数にHogeを指定でき,MyObservbableには無いがHogeにはあるメソッドを呼び出せる.
public void update(Hoge updated, Object args[]) {
  updated.hogeMethod();
}
MyObservableは,今回は適当にObserverの登録や削除メソッドなどを記述しておいた.
また,自分自身用のオブザーバ以外を登録できないように,ここでも総称型を使用している.
public interface MyObservable<MyObservable> {
これを実装するのがHoge.
MyObservableを実装するメソッドは,ObserveHelperに委譲している. そのObserveHelper.
MyObserverを総称型にしているので,そのupdateメソッド呼び出しに備えて,ObserveHelperも総称型にする必要がある.
public class ObserveHelper<MyObservable> {
そして,MyObserverのupdateメソッド呼び出しの際には,総称型(ここではメンバmyObservableが総称型)で呼び出す.
public void notify(Object args[]) {
  for(MyObserver<MyObservable> myObserver : myObservers) {
    myObserver.update(myObservable, args);
  }
}
あとは総称型を使用してこれらをnewして動かす.
総称型を使用してなんとかキャストを使用せず,監視対象と監視者のペアをコンパイラで検出できるような仕組みができた. だが,総称型のオンパレードでちょっと分けがわからないきがしないでもない.
matsu(C)
Since 2002
Mail to matsu