2
3

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で構築するオブザーバーパターン:リアクティブ設計の基盤

Posted at

概要

**オブザーバーパターン(Observer Pattern)**は、
あるオブジェクト(Subject)の状態変化に応じて、
複数の依存オブジェクト(Observer)へ通知を送る仕組みを提供する設計パターンである。

この構造はGUIイベント、ログ監視、リアルタイム通知、Pub/Subモデルのようなリアクティブシステムの中核を成す。

本稿では、Pythonでオブザーバーパターンを簡潔かつ強靭に構築する実装例を通じて、
関心の分離とリアクティブ設計の本質を解説する。


1. なぜObserverが必要か?

❌ 状態変化を監視するコードが至る所に散在

def update_ui(data):
    if data.changed:
        refresh_ui()

def log_change(data):
    if data.changed:
        write_log()

状態の変更と通知のロジックが分離されておらず、再利用や拡張が困難


✅ オブザーバーパターンで通知をイベント化

subject = Subject()
subject.attach(LoggerObserver())
subject.attach(UiObserver())

subject.set_state("UPDATED")

状態の変更は1箇所で済み、あらゆるObserverが自動的に同期


2. 基本構成と実装例

✅ 抽象的なSubjectとObserver定義

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

class Subject:
    def __init__(self):
        self._observers = []

    def attach(self, obs: Observer):
        self._observers.append(obs)

    def detach(self, obs: Observer):
        self._observers.remove(obs)

    def notify(self, data):
        for obs in self._observers:
            obs.update(data)

✅ 具象SubjectとObserverの実装

class DataSource(Subject):
    def __init__(self):
        super().__init__()
        self._data = None

    def set_data(self, value):
        self._data = value
        self.notify(self._data)

class Logger(Observer):
    def update(self, data):
        print(f"[LOG] Data updated to: {data}")

class Notifier(Observer):
    def update(self, data):
        print(f"[NOTIFY] Sending update for: {data}")

✅ 実行

source = DataSource()
source.attach(Logger())
source.attach(Notifier())

source.set_data("Event X")

3. ユースケース:現場での適用例

✅ フロントエンドにおけるUIバインディング

  • 状態(Store)をSubjectとして定義
  • 各ViewコンポーネントがObserverとして登録
  • 状態が変更されるとUIが自動更新

✅ バッチ処理におけるログ通知の分離

job = BatchJob()
job.attach(SlackNotifier())
job.attach(DBLogger())
job.run()

ロジックと通知が疎結合になるため、構成変更が容易


✅ データパイプライン内でのHook実装

  • データ流通の各ステップでObserverが登録され、特定条件下でアクションを実行

4. Python的に発展させる:デコレータで動的通知化

def observable(method):
    def wrapper(self, *args, **kwargs):
        result = method(self, *args, **kwargs)
        self.notify(result)
        return result
    return wrapper

class SmartSource(Subject):
    @observable
    def set(self, value):
        self._value = value

通知ロジックを分離し、宣言的な実装に昇華可能


5. よくある誤用と対策

❌ Observerが状態を変更し、副作用ループが発生

→ ✅ 通知対象は「読み取り専用」にするか、再帰呼出しの防止策を明示的に設計


❌ オブザーバーが密に結合されている

→ ✅ Observerは update(data) のみを受け取る設計とし、データ依存を減らす


❌ 無制限なObserver追加によりパフォーマンス劣化

→ ✅ detach() を正しく設計し、ライフサイクルを明示的に制御


結語

オブザーバーパターンは、**リアクティブなシステム設計における「関心の分離」と「反応の自動化」**を担保する構造である。

  • 状態の変化と振る舞いの連動を宣言的に設計
  • コンポーネント間の結合度を最小限にし、テスト・拡張を容易にする
  • GUI、通知、バッチ、非同期処理まで多様なドメインに対応

Pythonicとは、“状態の変化を手続きでなく構造で伝播させる”ことであり、
オブザーバーパターンはその思想を、シンプルかつパワフルに体現する設計である。

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?