Observer パターン


Observer パターンとは

オブジェクト間の1対多の依存関係を定義し、あるオブジェクトの状態が変化すると、それに依存している全てのオブジェクトが自動的に状態の変更の通知を受けるようにします。

Observerインターフェースと具象クラス

public interface Observer {
    void notifyUpdate();
}
public class ConcreteObserver1 implements Observer {
    @Override public void notifyUpdate() {
        System.out.println("ConcreteObserver1");
    }
}
public class ConcreteObserver2 implements Observer {
    @Override public void notifyUpdate() {
        System.out.println("ConcreteObserver2");
    }
}

Subjectインターフェースと具象クラス

public interface Subject {
    void notifyObservers();
    void addObserver(Observer o);
    void deleteObserver(Observer o);
}
public class ConcreteSubject implements Subject {

    private List<Observer> observers = new ArrayList<Observer>();
    
    @Override public void addObserver(Observer o) {
        observers.add(o);
    }

    @Override public void deleteObserver(Observer o) {
        observers.remove(o);
    }

    @Override public void notifyObservers() {
        for(Observer o : observers) {
            o.notifyUpdate();
        }
    }
}

実行ソース

    Subject subject = new ConcreteSubject();
    subject.addObserver(new ConcreteObserver1());
    subject.addObserver(new ConcreteObserver2());

    subject.notifyObservers();

実行結果

ConcreteObserver1
ConcreteObserver2

subject の変更が 2 つの Observer に通知されています。

もう一つの形

複数のクラスの変更を1つのクラスに伝えたい場合は ConcreteSubject と同様なクラスを2つ作る。

  • ConcreteSubjectA implements Subject
  • ConcreteSubjectB implements Subject
    Observer o = new ConcreteObserver();

    Subject subjectA = new ConcreteSubjectA();
    subjectA.addObserver(o);
    Subject subjectB = new ConcreteSubjectB();
    subjectB.addObserver(o);
        
    subjectA.notifyObservers();  // subjectAの変更が通知される

subjectA か subjectB の変更が1つの Observer に通知されるようにすることもできます。

Java の標準 Observer パターン

Observer パターンは良く使われるため、Javaの標準APIとして提供されています。

  • java.util.Observer
  • java.util.Observable

実装はこんな感じ。

public class ConcreteObserver implements Observer {
    @Override public void update(Observable o, Object arg) {
        System.out.println(o.getClass().getSimpleName() + " " + arg);
    }
}
public class ConcreteSubject extends Observable {
    public void publish() {
        setChanged();
        notifyObservers("ARG");
    }
}

setChanged()で変化したことをマーキングしないとnotifyObserversを呼び出しても処理が行われません。

実行コード

    ConcreteSubject subject = new ConcreteSubject();
    subject.addObserver(new ConcreteObserver());
    subject.publish();

実行結果

ConcreteSubject ARG