nabroux's Obsidian vault, published.

Astro Techbook

語言
中文

Observer Pattern

my-notes/low-level-design-lld/design-patterns/behavioral-patterns · ZH

translationKey: observer-pattern #low level design #design pattern #behavioral pattern #mark

類型:Behavioral Pattern 別名:Publish–Subscribe(發布 / 訂閱模式)、Listener Pattern(監聽者模式)

💡 1. 定義(Definition)

Observer Pattern 讓一個物件(Subject)可以自動通知多個依賴它的物件(Observers), 當它的狀態改變時,所有觀察者都會收到更新。

📘 換句話說:

「一個人更新 → 一群人自動收到通知」 類似 YouTube 訂閱、事件監聽、社群動態推播。


🎯 2. 問題背景(Problem Statement)

假設你有一個「股票價格更新系統」:

  • 當價格改變時,系統需要通知:
    • EmailService
    • SMSService
    • LINE Bot
    • Logging Service

如果你寫成:

price.update()
email.send()
sms.send()
line.send()
logger.log()

❌ 問題:

  • 每增加一個通知方式,你就要改 price.update() 這段程式碼
  • 違反 開放封閉原則(OCP)
  • 「通知邏輯」和「價格邏輯」耦合在一起
  • 測試與維護變困難

你希望:

  • 新增 / 移除監聽者不影響 Subject
  • Subject 不知道每個 Observer 的細節
  • 讓通知流程自動觸發,而非手動呼叫

✅ 解法:

讓 Observers 自己「訂閱」 Subject。 Subject 的狀態改變後,會主動通知所有 Observers。


⚙️ 3. 解決方案(Solution)

將「狀態持有者」與「需要知道狀態的物件」分離。 Subject 負責管理 Observer 名單,並在變更時呼叫它們的 update()。

這樣:

  • Subject 不需要知道 observers 是誰、要做什麼
  • Observers 可以被動更新
  • 可自由增刪監聽者
  • 系統更鬆耦合

🧱 4. 結構與角色(Structure & Participants)

角色 職責
Subject 保存狀態、管理 observer 名單
Observer 定義接收更新的方法
ConcreteSubject 實作 Subject,當狀態改變時通知 observers
ConcreteObserver 實作 observer 處理邏輯
Client 訂閱 / 取消訂閱、觸發流程
classDiagram class Subject { +attach(observer) +detach(observer) +notify() } class Observer { +update(data) } class ConcreteSubject { +set_state() +get_state() } class ConcreteObserverA { +update(data) } class ConcreteObserverB { +update(data) } Subject <|-- ConcreteSubject Observer <|-- ConcreteObserverA Observer <|-- ConcreteObserverB ConcreteSubject --> Observer

🧩 5. 程式碼範例(Python)

🧱 範例:股票價格通知(Stock Price Observer)

# === Observer 介面 ===
class Observer:
    def update(self, price):
        raise NotImplementedError


# === Subject ===
class StockPrice:
    def __init__(self):
        self._observers = []
        self._price = None

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

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

    def set_price(self, price):
        print(f"📈 Stock price updated: {price}")
        self._price = price
        self.notify()

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


# === Observers ===
class EmailNotifier(Observer):
    def update(self, price):
        print(f"📧 Email sent → price: {price}")

class SMSNotifier(Observer):
    def update(self, price):
        print(f"📩 SMS sent → price: {price}")

class LineNotifier(Observer):
    def update(self, price):
        print(f"💬 LINE message sent → price: {price}")


# === Client Code ===
price = StockPrice()

price.attach(EmailNotifier())
price.attach(SMSNotifier())
price.attach(LineNotifier())

price.set_price(150)
price.set_price(180)

輸出:

📈 Stock price updated: 150
📧 Email sent → price: 150
📩 SMS sent → price: 150
💬 LINE message sent → price: 150

📈 Stock price updated: 180
📧 Email sent → price: 180
📩 SMS sent → price: 180
💬 LINE message sent → price: 180

💡 Subject 完全不知道 observers 的細節 (是 Email? 是 SMS? 是 LINE? 完全不重要)

🧠 6. 實際應用場景(Real-world Use Cases)

場景 實例
🔔 Event System DOM addEventListener、Node.js EventEmitter
📨 訊息通知系統 Email / SMS / Webhook / LINE Bot 多管道通知
🧠 AI Pipeline preprocessor → inference → postprocessor 事件鏈
🔄 資料同步 Redis Pub/Sub、Kafka、RabbitMQ(本質即 Observer)
🖥 GUI Frameworks 按鈕點擊、狀態改變事件(Qt, Tkinter, SwiftUI)
📊 監控與告警系統 CPU 波動觸發多個告警(Slack、PagerDuty、Webhook)
🏦 金流 / 訂單流程 訂單狀態更新後 → 觸發一連串通知與事件

⚖️ 7. 優點與缺點(Pros & Cons)

優點 缺點
✅ 完全符合 OCP,新增 observer 不改主程式 ❌ 調試更困難(呼叫鏈較隱晦)
✅ 多對多通知,鬆耦合 ❌ 可能導致「通知風暴」
✅ 高擴展性、彈性 ❌ 順序性不可控(對某些應用是缺點)
✅ 非同步系統架構核心 ❌ 必須管理訂閱/退訂,否則容易記憶體洩漏

🔍 8. 與其他模式比較(Comparison)

模式 差異
Observer 一對多通知,事件驅動
Mediator 集中化協調,避免物件互相引用
Publisher / Subscriber(Pub/Sub) Observer 的分散式版本,透過 Message Broker
Chain of Responsibility 順序處理請求,一次一個 handler

💡 記法:

  • Observer:通知所有訂閱者
  • Pub/Sub:透過 Broker 消息分發
  • CoR:一個個處理
  • Mediator:大家都找仲介(中心)

🧭 9. 實務設計指引(Design Tips)

  • ✅ 當你有「一對多」的狀態同步需求 → 用 Observer
  • ✅ 適合 event-driven 系統(後端非常常見)
  • 💬 Node.js、前端框架、MQ 都內建 Observer 概念
  • 🚫 若通知量大,應改用 Kafka / RabbitMQ(Pub/Sub)替代
  • 🚫 不要讓 Observer 裡面做太重的事,否則會拖慢整個 Subject

🧮 10. 面試考點(Interview Insights)

問題 回答重點
Observer 解決什麼問題? 一對多通知、自動同步、鬆耦合
Observer vs Pub/Sub? Pub/Sub 透過 message broker,兩者不同層
Observer 適用情境? 通知系統、監控、GUI 事件、狀態同步
Python 如何實現? 訂閱名單 + update() 呼叫
缺點? 調試困難、訂閱管理麻煩、可能有通知風暴

✅ 11. 一句話總結(One-liner Summary)

Observer Pattern 是所有事件系統、通知、狀態同步的基礎, 一個動作觸發多個反應,就是觀察者模式的精髓。


📚 12. 延伸閱讀(Further Reading)

  • 📘 Design Patterns: Elements of Reusable Object-Oriented Software
  • 🧩 Refactoring.Guru – Observer Pattern![Attachment.tiff](file:///Attachment.tiff)
  • 🧱 Example: Node.js EventEmitter, Redis Pub/Sub, Webhooks

尚無其他語言版本