# 前言 本系列的第7篇 這次是觀察者模式(Observer Pattern) # 觀察者模式 一種行為型設計模式,它定義了一種一對多的依賴關係,即當一個物件(稱為「主題」或「被觀察者」)的狀態發生改變時 所有依賴它的物件(稱為「觀察者」)都會自動得到通知並更新。 觀察者模式的結構 1. 主題 / 被觀察者(Subject): 被觀察的物件,通常包含一個觀察者的列表,並提供添加、移除觀察者的方法。 當主題狀態發生變化時,它會遍歷這個列表並通知所有觀察者進行相應的操作。 2. 訂閱者 / 觀察者(Observer): 所有依賴於主題的物件,它們需要訂閱主題,以便在主題狀態變化時得到通知。 觀察者實現了更新接口,並在接到通知後執行特定的更新邏輯。 這次的實作情境是實況主與跟隨者的互動關係 當實況主發送了貼文等狀態,跟隨者會收到通知 也就是通知或訂閱系統 ```python= from abc import ABC, abstractmethod class Observer(ABC): # 觀察者 / 訂閱者 介面 @abstractmethod def update(self, post_content: str, streamer_name: str): pass class Follower(Observer): # 追蹤者 def __init__(self, username: str): self.username: str = username def update(self, post_content: str, streamer_name: str): self.post_content: str = post_content self.notice_msg: str = f"Hi, {self.username}, The streamer '{streamer_name}' you follow has posted a new update. 「{self.post_content}」" print(self.notice_msg) class Subject(ABC): # 被觀察者 / 主題介面 @abstractmethod def register_follower(self, follower: Observer): pass @abstractmethod def remove_follower(self, follower: Observer): pass @abstractmethod def notify_follower(self): pass class Streamer(Subject): # 實況主 def __init__(self, streamer_name: str): self.followers: list[Follower] = [] self.streamer_name: str = streamer_name def register_follower(self, follower: Observer): self.followers.append(follower) def remove_follower(self, follower: Observer): self.followers.remove(follower) def notify_follower(self, cur_post: str): for follower in self.followers: follower.update(cur_post, self.streamer_name) if __name__ == '__main__': asiagodtone = Streamer("asiagodtone") follower_alice = Follower("Alice") follower_bob = Follower("Bob") # 訂閱實況主(增加追隨者) asiagodtone.register_follower(follower_alice) asiagodtone.register_follower(follower_bob) # 發送通知 asiagodtone.notify_follower("1111") # 取消訂閱(移除追隨者) asiagodtone.remove_follower(follower_alice) # 再次發送通知 asiagodtone.notify_follower("22222") ``` 執行後可得到以下輸出 ``` Hi, Alice, The streamer 'asiagodtone' you follow has posted a new update. 「1111」 Hi, Bob, The streamer 'asiagodtone' you follow has posted a new update. 「1111」 Hi, Bob, The streamer 'asiagodtone' you follow has posted a new update. 「22222」 ``` 可以看到Alice取消訂閱後 就不再收到來自asiagodtone的通知了 # 心得 也是很常見的設計模式 但這次是第一次實作 最初實作時總覺得有點奇怪 為什麼註冊跟移除這兩個method是寫在`Subject`而不是`Observer`中 明明控制要不要關注`Subject`的是`Observer`才對 後來問了chatGPT並參考了許多文章 主因是**通知是由被觀察者發起的,必須知道要發送給哪些觀察者** 通過將註冊與移除的method寫在`Subject`中,進行集中化的管理 能夠更好的控制有哪些觀察者 除此之外 也能保持被觀察者和觀察者之間的低耦合性。被觀察者只知道有一組觀察者對其感興趣,但它不需要了解觀察者的具體類型或內部邏輯。