※個人的な学習メモです。
Observerパターンは、知っていると非常に便利なデザインパターンです。
解説
Observer(オブザーバー)とは観察者という意味です。
観察される、とあるオブジェクトをここではSubject(サブジェクト・観察される側)とすれば、Subjectに変化があった場合にSubjectに依存するオブジェクトに通知を行う仕組みだそうです。
画面などの操作でイベントを受取り画面を更新し直したり、外部のモジュールなりシステムへ通知したりする用途で使われます。
※Publish-Subscribeパターン(発行-購読パターン)と呼ばれることもあります。
実際のコード例(Java)
// Observer(通知される側)
interface Observer {
void update(String msg);
}
// Subject(通知する側)
class Subject {
private List<Observer> observers = new ArrayList<>();
void add(Observer o) { observers.add(o); }
void notifyAll(String msg) {
for (Observer o : observers) o.update(msg);
}
}
// 具体的なObserver
class User implements Observer {
private String name;
User(String name) { this.name = name; }
public void update(String msg) {
System.out.println(name + " received: " + msg);
}
}
// 実行例
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
subject.add(new User("田中"));
subject.add(new User("佐藤"));
subject.notifyAll("イベント発生!");
}
}
コードの説明
SubjectはObserverを管理するリストを保持しており、Subjectの状態が変化したときにリスト内のObserverに通知を行う。
Observerが増加する条件は「通知を受け取る条件が増えた時」であり、新聞の購読に例えるならば「新しい新聞を受け取る時」である。逆にObserverが減少する条件は「通知を受け取る条件が減った時」であり「新聞の契約を1つ減らした時」である。
つまり、Subjectに登録されているすべてのObserverに一斉に通知が送信されます。Observerの先には外部モジュールなり外部システムとの通信処理があり、メール通知だったりSMS通知だったりするのかもしれません。
サンプルコードでは、田中さんや佐藤さんに一斉に”イベント発生”の通知を行っています。
疑問:なぜSubject内部にObserverがあるんだろう?
ここで疑問がでてきます。
Subject内部にObserverが在るのは、現実世界のモデリングという意味では変じゃないですか?(外部在るものを呼び出すようにしてはいけないのですか?)
結論から言えば、、、Observerが格納されるリストはObserverそのものではなく、Observerインスタンスへの参照に過ぎない。Subjectを新聞社だとすると、Observerリストは購読者の名簿であり、Observerの実体は外部に在る⋯ということになるので「ObserverはSubjectの外部に在るべき」という思想はObserverパターンで問題なく実現ができていることになる。
結論:Subject内にはObserverの参照があるのみ。実際にはObserverは外部にあると考えてよい。
疑問:StrategyパターンとObserverパターンって似てません?
結論から言えば非常に似ているが違う点もある。
StrategyもObserverも共通のインターフェースを持っており、異なる振る舞いを実装できるようにしている。各インスタンスの実装はカプセル化されており、メタクラスからは見えない(Strategyの場合はContext、Observerの場合はSubjectが、メタクラスにあたる)。
最も大きく違うのは目的で、Strategyパターンは差し替え可能な処理/アルゴリズムを個々に柔軟に切り替えることにあり(つまりメタクラスと1対1の関係になる)、Observerパターンは複数のObserverに一斉通知を行う(つまりメタクラスと1対多の関係になる)。


コメント