Observer パターン

出典: フリー百科事典『ウィキペディア(Wikipedia)』
ナビゲーションに移動 検索に移動

Observer パターン(オブザーバ・パターン)とは、プログラム内のオブジェクトのイベント( 事象 )を他のオブジェクトへ通知する処理で使われるデザインパターンの一種。

通知するオブジェクト側が、通知されるオブジェクト側に観察(: observe)される形になる事から、こう呼ばれる。

出版-購読型モデルとも呼ばれる。暗黙的呼び出しの原則と関係が深い。

分散イベント処理システムの実装にも使われる。言語によっては、このパターンで扱われる問題は言語が持つイベント処理構文で処理される。

クラス図[編集]

このパターンの基本は、イベントを通知される側の1つ以上のオブジェクト(オブザーバ 又リスナーと呼ぶ)を、通知する側(サブジェクトと呼ぶ)のオブジェクトに登録する事である。そして通知関数が、抽象メソッドになっている事が重要である。

以下に、その構造をUMLクラス図で視覚化したものを示す。

Observer-pattern-class-diagram.png

各クラスの解説[編集]

このパターンに登場する各インターフェース・メソッド・インターフェースの実装クラスを、以下で解説する。

Subject[編集]

イベントを通知するオブジェクト側のインターフェース。1つ以上のObserver( イベントを通知されるオブジェクト側のインターフェース )の登録・削除・通知の関数書式の体裁を提供する。

以下の抽象メソッドを持つ:

  • addObserver - Subjectが持つ「 通知を受け取るObserver群 」に、新たなObserverを加える。
  • deleteObserver - 上述で加えられた物を削除する。
  • notifyObservers - Subjectが持つ「 通知を受け取るObserver群 」に、Observer::notify() を呼んでイベントを通知する。

上のUMLクラス図では、Subjectがインターフェースと実装クラスに分かれているが、パターン要件でない。インターフェースを使わずクラスを直接実装する事もある。

ConcreteSubject[編集]

Subjectの実装クラス。通知対象であるObserver群を持つ。各Observerが受け取る通知に関する処理を司る。notifyObservers() を呼ぶと、Observer群の1つ以上にイベントを通知する。

Observer[編集]

イベントを通知される側のインターフェース。以下の抽象メソッドを持つ:

  • notify - Observerにとっては通知を受け取る処理、このメソッドを呼ぶSubjectにとっては通知を送る処理、と言える。このメソッドの個数や各書式は、通知内容により様々である。

ConcreteObserver[編集]

Observerの実装クラス。

典型的用法[編集]

  • ユーザーが何らかの操作をするなどの外部イベントを待つ。イベント駆動型プログラミング参照。
  • あるオブジェクトの属性値の変化を待つ。なお、複数の属性値の変化でコールバック関数を呼び出すようにしているとイベントの連鎖的発生を引き起こす。
  • メーリングリストで、何らかのイベント(新製品情報など)があったとき、購読者リストに登録している人にメッセージを送る。

Observer パターンは Model View Controller (MVC) パラダイムの実装に使われることも多い。MVC では、モデルとビューの連携に Observer パターンが使われる。通常、モデルの変化を引き金として、ビュー(オブザーバ)にそれを通知する。

擬似コード[編集]

Python[編集]

以下の擬似コードPython 風文法で Observer パターンを記述したものである。

 class Listener:
     def __init__(self, name, subject):
         self.name = name
         subject.register(self)
 
     def update(self, event):
         print self.name, "received event", event

 class Subject:
     def __init__(self):
         self.listeners = []
 
     def register(self, listener):
         self.listeners.append(listener)
 
     def unregister(self, listener):
         self.listeners.remove(listener)
 
     def notify_listeners(self, event):
         for listener in self.listeners:
             listener.update(event)

 subject = Subject()
 listenerA = Listener("<listener A>", subject)
 listenerB = Listener("<listener B>", subject)
 # subject には2つのリスナーが登録されている。
 subject.notify_listeners ("<event 1>")
 # 出力:
 #     <listener A> received event <event 1>
 #     <listener B> received event <event 1>

Java[編集]

ロックを避けるため、CopyOnWriteArraySetを使用する。

 public interface Listener {
     public void onEvent();
 }

 import java.util.concurrent.CopyOnWriteArraySet;
 
 public class Subject {
     private Set<Listener> listenerSet = new CopyOnWriteArraySet<Listener>();
     
     public void addListener(Listener listener) {
         listenerSet.add(listener);
     }
 
     private void notifyListeners() {
         for (Listener listener : listenerSet) {
             listener.onEvent();
         }
     }
 }

実装[編集]

Observer パターンは各種ライブラリやシステムに実装されている。特にGUIツールキットには必ず含まれる。

関連項目[編集]

外部リンク[編集]