KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

Python基礎 オブジェクト指向18(Observer) 振る舞いに関するデザインパターン

登録日 :2025/11/15 11:34
カテゴリ :Python基礎

Observer

観測対象のオブジェクトの状態変化が発生した際に、複数の観測者に対して通知を行うパターン

観測よりも通知に重点が置かれており、Publish(発行)-Subscribe(購読)パターンと呼ばれることもある

  • 振る舞いに関するデザインパターン

構成要素

観測者
Observer ( Subscriberと呼ばれることもある )

  • 観測者となる抽象クラスまたはインターフェース
  • 通知を受け取るためのAPIを定義

ConcreteObserver

  • Observerを継承(実装)する子クラス
  • 観察対象の通知から現在の状態を取得して、状態に応じた処理を行う

観測対象側
Subject

  • 観測対象となる抽象クラスまたはインターフェース
  • 属性にObserverを保持
  • 観察者の追加/削除/通知を行うための共通メソッド
  • 具体的な処理をするための抽象メソッドを定義

ConcreteSubject

  • Subjectを継承(実装)する子クラス
  • 具体的な処理をするためのメソッドを実装

オブジェクト指向的要素

  • 「継承」「ポリモーフィズム」を利用react値あパターン

  • SubjectとConcreteSubject, ObserverとConcreteObserverが継承(実装)関係

  • SubjectはObserverの共通APIを利用して通知を行うことで、具体的な観測者クラスの追加・削除・切り替え等が可能になる

メリット・デメリット

メリット

  • 実行時に観測者の変更が可能
  • 観測者と観測対象のつながりを弱めることができる
  • 新たな観測対象の追加や削除や修正が容易になる

デメリット

  • 通知の順番に依存しない実装にしなければ予期せぬバグが発生する可能性がある

使い所

  • 状態変化に応じた処理を行う場合
     例)ニュースサイト、SNS、Angularに採用されているRxJS

  • オブジェクトを一時的に監視したい場合

  • 並列処理を実装する場合のイベントの監視

サンプル

人気商品の入荷通知

from abc import ABCMeta, abstractmethod


class Observer(metaclass=ABCMeta):
    @abstractmethod
    def update(self, _name: str):
        pass


class StoreObserver(Observer):
    def update(self, _name: str):
        print(f"{_name}が入荷されました。仕入れが可能です")


class PersonalObserver(Observer):
    def update(self, _name: str):
        print(f"{_name}が入荷されました。購入が可能です")


class ItemSubject(metaclass=ABCMeta):
    def __init__(self, _name: str):
        self.__name = _name
        self.__observers: list[Observer] = []

    def attach(self, _observer: Observer):
        self.__observers.append(_observer)

    def detach(self, _observer: Observer):
        self.__observers.remove(_observer)

    def notify(self):
        for obs in self.__observers:
            obs.update(self.__name)

    @abstractmethod
    def restock(self):
        pass


class TvGameSubject(ItemSubject):
    def __init__(self, _name: str):
        super().__init__(_name)
        self.__in_stock = False

    def restock(self):
        print("TV Gameの入荷")
        self.__in_stock = True
        self.notify()


if __name__ == "__main__":
    store = StoreObserver()
    person = PersonalObserver()

    tv_game = TvGameSubject("FF 7")
    tv_game.attach(store)
    tv_game.attach(person)
    tv_game.restock()

    tv_game.detach(person)
    tv_game.restock()