※個人的な学習メモです。
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対多の関係になる)。
コメント