概要
Observer(オブザーバー)パターンは、
あるオブジェクトの状態変化に応じて、依存する複数のオブジェクトへ自動的に通知・更新を行う設計パターンである。
GUIイベント、データバインディング、通知システムなど、**「誰かが変わったら誰かが反応する」**ような仕組みで重要な構造である。
1. なぜObserverが必要か?
❌ 依存先を直接呼び出すと結合度が高く、変更が困難
def update_temperature(new_temp):
label.set_text(new_temp)
logger.log(new_temp)
→ 変更箇所が増えるたびに呼び出し元が肥大化・複雑化する
✅ 「通知を送る」ことだけに集中し、反応は登録されたオブザーバー側で自律的に行う
subject.attach(observer)
subject.notify()
→ 依存関係を疎に保ち、柔軟な拡張と動的な反応が可能に
2. 基本構造
✅ Subject(通知元)
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, *args, **kwargs):
for observer in self._observers:
observer.update(*args, **kwargs)
✅ Observer(通知先)
class Observer:
def update(self, *args, **kwargs):
raise NotImplementedError
✅ ConcreteObservers(具体的な反応)
class Logger(Observer):
def update(self, value):
print(f"[Logger] 新しい温度: {value}")
class Display(Observer):
def update(self, value):
print(f"[Display] 表示を更新: {value}")
✅ 使用例
subject = Subject()
subject.attach(Logger())
subject.attach(Display())
subject.notify(25)
出力:
[Logger] 新しい温度: 25
[Display] 表示を更新: 25
3. Python的応用:関数ベースのObserver登録も可能
class Event:
def __init__(self):
self._handlers = []
def subscribe(self, fn):
self._handlers.append(fn)
def fire(self, *args, **kwargs):
for handler in self._handlers:
handler(*args, **kwargs)
# 使用例
event = Event()
event.subscribe(lambda x: print(f"通知A: {x}"))
event.subscribe(lambda x: print(f"通知B: {x}"))
event.fire("変化しました")
→ シンプルな用途では関数を購読させる形でObserverを構成できる
4. 実務ユースケース
✅ GUIアプリケーションのイベントハンドリング
→ ボタンのクリック・入力変更に対してリアクティブに反応
✅ データ変更に応じた画面更新(MVVM, Flux)
→ ViewModelやStateに応じてViewが自動更新される
✅ 通知システム・アラート配信
→ センサー・監視ツールからの通知を複数の宛先に展開
✅ ゲームオブジェクトの監視と相互作用
→ あるオブジェクトの変化に対して他オブジェクトが連動して動く
5. よくある誤用と対策
❌ SubjectがObserverの中身に依存している
→ ✅ Observerはインターフェースとして設計し、Subjectは知らなくてよい
❌ 通知の順番や失敗が原因で状態不整合が起きる
→ ✅ 通知順や例外処理を設計時に明確にしておく
❌ 無限ループ・循環参照によるスタックオーバーフロー
→ ✅ 再帰的通知の設計に注意し、必要ならガードロジックを実装
結語
Observerパターンとは、“変化を見張り、反応する知性”を分離・再利用可能な構造で表現する技法である。
- 状態の変化を他オブジェクトに伝播させ、疎結合でリアクティブな構造を構築
- オブザーバー側が「何をするか」を自由に定義可能で、柔軟な連携が可能
- Pythonでは関数ベース・クラスベースいずれも表現しやすく、動的な拡張性に優れる
Pythonicとは、“変化を直接操作するのではなく、通知によって委ねること”。
Observerパターンはその反応性を、設計の自律性として昇華する構造である。