# 前言
本系列的第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`中,進行集中化的管理
能夠更好的控制有哪些觀察者
除此之外
也能保持被觀察者和觀察者之間的低耦合性。被觀察者只知道有一組觀察者對其感興趣,但它不需要了解觀察者的具體類型或內部邏輯。