0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するObserverパターン:イベント通知の仕組みを構築する

Posted at

概要

Observer(オブザーバー)パターンは、
あるオブジェクト(Subject)の状態変化を、それに依存する複数のオブザーバー(Observer)に自動で通知するためのデザインパターンである。

イベント駆動型の設計、UI更新、リアルタイム通知など、状態変化に対する反応的な処理を整理するために極めて有効である。


1. なぜObserverが必要か?

❌ 状態変化を検知するたびに明示的に通知処理を呼び出す

user.set_status("online")
notifier.send_email()
ui.update_status()
logger.log()

→ 通知処理が散在し、依存性が高く、変更に弱い構造


✅ 状態の変更を一元化し、自動で関係者に通知する構造へ

user.set_status("online")
# → 登録されたすべてのオブザーバーが反応

送信者(Subject)と受信者(Observer)の疎結合化を実現


2. 基本構造

✅ Observerインターフェース

class Observer:
    def update(self, subject):
        raise NotImplementedError

✅ Subject(通知元)

class Subject:
    def __init__(self):
        self._observers = set()

    def attach(self, observer: Observer):
        self._observers.add(observer)

    def detach(self, observer: Observer):
        self._observers.discard(observer)

    def notify(self):
        for observer in self._observers:
            observer.update(self)

✅ ConcreteSubject(状態を持つ具体クラス)

class User(Subject):
    def __init__(self, name):
        super().__init__()
        self.name = name
        self._status = "offline"

    def set_status(self, status):
        self._status = status
        self.notify()

    def get_status(self):
        return self._status

✅ ConcreteObserver(通知を受けて反応する側)

class Logger(Observer):
    def update(self, subject):
        print(f"[Logger] {subject.name} is now {subject.get_status()}")

class Notifier(Observer):
    def update(self, subject):
        print(f"[Notifier] Sending notification: {subject.name} is {subject.get_status()}")

✅ 使用例

user = User("Alice")
logger = Logger()
notifier = Notifier()

user.attach(logger)
user.attach(notifier)

user.set_status("online")
user.set_status("away")

出力:

[Logger] Alice is now online
[Notifier] Sending notification: Alice is online
[Logger] Alice is now away
[Notifier] Sending notification: Alice is away

3. Python的応用:デコレータ的シグナルパターン

class Signal:
    def __init__(self):
        self._handlers = []

    def connect(self, func):
        self._handlers.append(func)

    def emit(self, *args, **kwargs):
        for handler in self._handlers:
            handler(*args, **kwargs)

status_changed = Signal()

def send_alert(status):
    print(f"[Alert] User is {status}")

status_changed.connect(send_alert)
status_changed.emit("busy")

DjangoのSignal風の実装により、柔軟なリアクティブ処理が可能


4. 実務ユースケース

✅ GUIの状態変化によるUI部品の自動更新

→ ボタン押下、フォーム入力、画面遷移時のリアルタイム同期


✅ SNSやチャットアプリの通知システム

→ フォロー中ユーザーの行動に対する非同期通知


✅ IoTセンサーデータのストリーミング処理

→ センサー状態を監視・ログ・UIに自動反映


✅ モデルの状態変更に応じたView更新(MVC)

→ モデルが変更されると、登録されたViewにイベント通知が飛ぶ


5. よくある誤用と対策

❌ 通知処理の中で状態変更を行い、無限ループ発生

→ ✅ 再帰的な通知チェーンは設計的に遮断する


❌ ObserverがSubjectの内部構造に依存しすぎる

→ ✅ update(subject)の中で最低限のインターフェースだけを使う


❌ オブザーバーの登録解除を忘れるとメモリリーク

→ ✅ detach()の実行や弱参照による管理を検討


結語

Observerパターンとは、“変化を知るべき存在に、通知の流れを正しく届ける設計技法”である。

  • 状態変化に伴う反応処理を構造として設計し、通知の流れを一元化
  • 依存を減らしつつ、リアクティブなアプリケーション構造を可能に
  • Pythonではインターフェース不要の柔軟な実装が可能で、Signal/Slot/Hookなど多様な形で活用できる

Pythonicとは、“リアルタイムの変化に優雅に反応すること”。
Observerパターンはその変化の波を、秩序と意志を持って伝える構造である。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?