Observer パターン
Observer パターン(オブザーバ・パターン)とは、プログラム内のオブジェクトの状態を観察(observe)するようなプログラムで使われるデザインパターンの一種。出版-購読型モデルとも呼ばれる。暗黙的呼び出しの原則と関係が深い。
分散イベント処理システムの実装に主に使われる。言語によっては、このパターンで扱われる問題は言語が持つイベント処理構文で処理される。リアルタイムのアプリケーション配置の手段として興味深い機能である。
目次 |
クラス図 [編集]
このパターンの基本は、(オブザーバまたはリスナーと呼ばれる)1つ以上のオブジェクトを、(サブジェクトと呼ばれる)対象オブジェクトが発生するイベントを観察するために登録する。イベントを発生するオブジェクトは一般に複数のオブザーバを管理する。
以下に、その構造をUMLで描いたものを示す。
各クラスの解説 [編集]
このパターンに登場する各クラスを以下で解説する。各クラスのメンバ関数が列挙されている。
Subject [編集]
オブザーバの登録・削除のインタフェースを提供するクラス。Subject クラスはオブザーバのリストを保持する。以下の関数を持つ:
- Attach - Subject を観察するオブザーバのリストに新たなオブザーバを追加する。
- Detach - オブザーバのリストからオブザーバを削除する。
- Notify - リストに登録されている各オブザーバの update() 関数を呼び出すことで変化を通知する。
ConcreteSubject [編集]
オブザーバが観察したいと考えている状態を提供する。上位クラス(すなわち Subject クラス)の Notify 関数を呼び出すことで、全オブザーバに状態変化を通知する。以下の関数を持つ:
- GetState - サブジェクトの状態を返す。
Observer [編集]
Subject からの更新通知を受け取る更新(update)インタフェースを定義するクラス。Observer クラスは実際のオブザーバの抽象クラスとして使われる。以下の関数を持つ:
- Update - 抽象関数。実際のオブザーバクラスでオーバーライドされる。
ConcreteObserver [編集]
実際のオブザーバクラス。ConcreteSubject の状態変化の通知を受ける。以下の関数を持つ:
- Update - サブジェクトがこの関数を呼び出すと、Concrete Observer が サブジェクトの Getstate 関数を呼び出してサブジェクトの状態情報を更新する。
イベントが発生すると、各オブザーバはコールバックを受け付ける。これは、オブザーバクラスの仮想関数(上の説明では、update())の場合もあるし、リスナー登録の際に渡される関数ポインタ(より一般的には関数オブジェクト)の場合もある。この通知関数にはいくつかの引数が渡され(発生したイベントを示す引数)、オブザーバがそれを利用する。
それぞれの実体のオブザーバは通知関数を実装し、その定義として実際にイベントを通知されたときの動作を記述する。
典型的用法 [編集]
- ユーザーが何らかの操作をするなどの外部イベントを待つ。イベント駆動型プログラミング参照。
- あるオブジェクトの属性値の変化を待つ。なお、複数の属性値の変化でコールバック関数を呼び出すようにしているとイベントの連鎖的発生を引き起こす。
- メーリングリストで、何らかのイベント(新製品情報など)があったとき、購読者リストに登録している人にメッセージを送る。
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ツールキットには必ず含まれる。
- Java Swing ライブラリは Observer パターンを多用している。
- Boost.Signals - C++ STL の拡張。signal/slot モデルを提供する。
- Qt - C++ フレームワークの signal/slot モデル。
- libsigc++ - C++ シグナルプログラミング・テンプレートライブラリ
- sigslot - C++ Signal/Slot ライブラリ
- XLObject - テンプレートベースの C++ signal/slot モデル
- GLib - C言語でのオブジェクトと signals/callbacks の実装(他のプログラミング言語用の実装もある)
- Exploring the Observer Design Pattern - C# と Visual Basic .NET による実装。delegates を利用。
- Using the Observer Pattern - REALbasic による実装
- flash.events - ActionScript 3.0 でのパッケージ(ActionScript 2.0 の mx.events パッケージの後継)
- YUI Event utility - カスタムイベントを Observer パターンで実装
- Py-notify - Python 実装
関連項目 [編集]
外部リンク [編集]
- A sample implementation in .NET
- Observer Pattern in Java
- Observer Pattern implementation in JDK 1.4
- Using the Observer Pattern in .NET
- Definition & UML diagram
- A discussion of fine-grained observers
|
|||||||||||
