cover

你有沒有寫過這種 code:資料一更新,就要手動呼叫五個不同的 function 去更新 UI、發通知、寫 log?然後每次加一個新的「需要被通知的人」,就要回去改那段 code?

這就是 Observer Pattern 要解決的問題。

先講結論

Observer 就是「訂閱/發布」機制。資料變了(Subject),自動通知所有訂閱者(Observer)。你不用管有幾個訂閱者、他們是誰——你只管發布,剩下的交給機制。

classDiagram
    class Subject {
        -observers : Observer[]
        +subscribe(observer) void
        +unsubscribe(observer) void
        +notify() void
    }
    class Observer {
        <<interface>>
        +update(data)* void
    }
    class ConcreteObserverA {
        +update(data) void
    }
    class ConcreteObserverB {
        +update(data) void
    }
    Subject --> Observer
    Observer <|.. ConcreteObserverA
    Observer <|.. ConcreteObserverB

實戰:新聞訂閱系統

class NewsCategory {
    constructor(categoryName) {
        this.categoryName = categoryName;
        this.subscribers = [];
    }
 
    subscribe(observer) {
        if (!this.subscribers.includes(observer)) {
            this.subscribers.push(observer);
        }
    }
 
    unsubscribe(observer) {
        this.subscribers = this.subscribers.filter(sub => sub !== observer);
    }
 
    notify(news) {
        for (const subscriber of this.subscribers) {
            subscriber.update(news);
        }
    }
 
    publish(news) {
        const fullNews = `[${this.categoryName}] ${news}`;
        console.log(`發布:${fullNews}`);
        this.notify(fullNews);
    }
}
 
class User {
    constructor(username) {
        this.username = username;
    }
 
    update(news) {
        console.log(`${this.username} 收到:${news}`);
    }
}
 
const sports = new NewsCategory('體育');
const user1 = new User('小明');
const user2 = new User('小華');
 
sports.subscribe(user1);
sports.subscribe(user2);
sports.publish('台灣隊奧運奪金!');
 
sports.unsubscribe(user1);
sports.publish('世界盃結果出爐'); // 只有小華會收到

你其實每天都在用 Observer

不騙你,這些東西底層都是 Observer Pattern:

  • DOM 事件addEventListener 就是在 subscribe
  • Node.js EventEmitteron('data', callback) 就是 Observer
  • RxJS Observable:整個 library 就是 Observer Pattern 的強化版
  • Vue/React 的響應式系統:資料一改,UI 自動更新

所以與其說「學 Observer Pattern」,不如說你是在理解這些工具背後的原理。

要注意什麼?

  • 記得取消訂閱:不然就是 memory leak。前端開發者最常犯的錯——component unmount 的時候忘了 unsubscribe
  • 別讓通知風暴搞死你:一個 Subject 有 1000 個 Observer,每次更新全部通知?考慮 debounce 或 batch update
  • 小心循環通知:A 通知 B、B 通知 A,然後 call stack overflow

Observer Pattern 就像 YouTube 的訂閱鈴鐺——你按了之後就不用一直去頻道主頁刷新,有新片自動通知你。只是現實中你訂閱了一百個頻道然後通知多到關掉


延伸閱讀