デザインパターン学習メモ:「Observer」


目的

GoF本より引用する。

あるオブジェクトが状態を変えたときに、それに依存するすべてのオブジェクトに自動的にそのことが知らされ、また、それらが更新されるように、オブジェクト間に一対多の依存関係を定義する。

別名、Publish-Subscribeパターン。

使用例としては、GoF本の例を借りると、グラフィックユーザインタフェースツールキットが挙げられる。

あるデータが変更された時に、リアルタイムでバーチャートやスプレッドシートを表現するオブジェクトに通知を行い、表示を変更することができる。

通知する側を"Subject"、通知される側を"Observer"と呼び、SubjectにObserverを登録しておくと、Subjectに変更があったときに自動的に通知がされる。

Subjectは登録されているオブジェクトの詳細は把握せず(Observerインタフェースを持つことしか知らない)、SubjectとObserverは密に結合しない。

実装例

Subject.java
public interface Subject {
    void attach(Observer observer);

    void detach(Observer observer);

    void notifyObservers(); // "notify"はObjectクラスで使用済みだった

    // observerへのnotify後、observerによって呼び出される
    // 戻り値の型は適切な型に変更する
    Object getState();
}
SubjectImpl.java
public class SubjectImpl implements Subject {
    List<Observer> observers = new ArrayList<Observer>();

    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        for (int i = 0; i < observers.size(); i++) {
            if (observers.get(i) == observer) {
                observers.remove(i);
            }
        }
    }

    @Override
    public void notifyObservers() {
        observers.forEach(observer -> observer.update(this));
    }

    @Override
    public Object getState() {
        // 適切な処理を実装する
        return null;
    }
}
Observer.java
public interface Observer {
    void update(Subject subject);
}
ObserverImpl.java
public class ObserverImpl implements Observer {

    @Override
    public void update(Subject subject) {
        Object object = subject.getState();
        // 適切な処理を実装する
    }
}

参考文献

  • エリック ガンマ、ラルフ ジョンソン、リチャード ヘルム、ジョン プリシディース(1999)『オブジェクト指向における再利用のためのデザインパターン 改訂版』本位田 真一、吉田 和樹 監訳、SBクリエイティブ