Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.
--Refactoring Guru
觀察者模式是一種行為型設計模式,它允許你定義一種訂閱的機制,以通知多個物件有關它們正在觀察的物件 的任何事件。
(圖片來源: Refactoring Guru)
觀察者模式通常用於解決以下問題和情境:
物件狀態的更新通知:
當一個物件的狀態發生變化,需要通知其他物件來執行相應的操作時,可以使用觀察者模式。這樣,物件之間可以保持解耦,subject(被觀察者)只需要知道觀察者的存在,而不需要知道具體的觀察者是誰。
事件處理:
在事件驅動的程式設計中,當事件發生時,需要通知多個事件處理器或監聽器來執行相應的操作。觀察者模式可以用來實現這種事件處理機制。
GUI(圖形用戶界面):
在圖形用戶界面中,常常需要監聽用戶的操作,例如按鈕點擊、滑鼠移動等等。觀察者模式可以用於設計和實現這些事件的處理。
資料推送:
當資料源有新數據可用時,需要將數據推送給多個接收者,例如即時通訊、訊息推送等場景中,觀察者模式可以有效地實現這種資料推送機制。
被觀察者(Subject):或是發布者(Publisher),也是被觀察的物件,它維護一個觀察者列表,可以添加、刪除和通知觀察者。
觀察者(Observer):也稱訂閱者(Subscribers),等待被通知的物件,當被觀察者的狀態發生變化時,觀察者會收到通知,並執行相應的操作。
具體被觀察者(Concrete Subject):主題的具體實作,它繼承自被觀察者介面並實作相關的方法。
具體觀察者(Concrete Observer):觀察者的具體實作,通常實現一個更新方法,以便在接收到通知時執行特定的操作。
假設我們作一個新聞通知系統
有不同主題的新聞時,會送通知到多個訂閱者(使用者)中
首先是被觀察者(Subject/Publisher),被觀察者是新聞發佈者,它負責維護一個觀察者(訂閱者)列表,以及通知這些觀察者當有新新聞可用時。被觀察者具有以下功能:
Attach(observer):允許觀察者註冊(訂閱)以接收新聞通知。
Detach(observer):允許觀察者取消註冊(取消訂閱),不再接收通知。
Notify():在新聞發佈時通知所有註冊的觀察者。
PublishNews(string news):這個方法用於發佈新聞。當新聞發佈時,它會記錄最新的新聞內容,然後呼叫 Notify() 通知所有訂閱者。
// 被觀察者 (Subject)
interface INewsPublisher
{
void Attach(INewsSubscriber observer);
void Detach(INewsSubscriber observer);
void Notify();
void PublishNews(string news);
}
再來是觀察者,觀察者是新聞訂閱者,它們接收新聞通知並處理新聞消息。
Update(news):當被觀察者通知有新消息時,觀察者執行此方法以處理並顯示新聞消息。
// 觀察者 (Observer)
interface INewsSubscriber
{
void Update(string news);
}
具體被觀察者(NewsPublisher),這是 NewsPublisher類別的實作,它實際上繼承自被觀察者介面(INewsPublisher)。
在這個具體被觀察者中,發佈者管理觀察者列表,並在新聞發布時通知觀察者。
// 具體被觀察者 (Concrete Subject)
class NewsPublisher : INewsPublisher
{
private List<INewsSubscriber> subscribers = new List<INewsSubscriber>();
private string latestNews;
public void Attach(INewsSubscriber observer)
{
subscribers.Add(observer);
}
public void Detach(INewsSubscriber observer)
{
subscribers.Remove(observer);
}
public void Notify()
{
foreach (var subscriber in subscribers)
{
subscriber.Update(latestNews);
}
}
public void PublishNews(string news)
{
latestNews = news;
Console.WriteLine($"新聞發佈: {news}");
Notify();
}
}
具體觀察者(NewsSubscriber)是 NewsSubscriber 類別的實作,它實際上繼承自觀察者介面(INewsSubscriber)。
每個具體觀察者代表一個新聞訂閱者,當被觀察者通知有新消息時,具體觀察者會執行 Update() 方法來處理並顯示新聞消息。
// 具體觀察者 (Concrete Observer)
class NewsSubscriber : INewsSubscriber
{
private string name;
public NewsSubscriber(string name)
{
this.name = name;
}
public void Update(string news)
{
Console.WriteLine($"{name} 收到新消息: {news}");
}
}
最後是我們的主程式:
class Program
{
static void Main()
{
INewsPublisher newsPublisher = new NewsPublisher();
// 新聞訂閱者
INewsSubscriber subscriber1 = new NewsSubscriber("訂閱者1");
INewsSubscriber subscriber2 = new NewsSubscriber("訂閱者2");
// 訂閱新聞主題
newsPublisher.Attach(subscriber1);
newsPublisher.Attach(subscriber2);
// 設定新消息並通知觀察者
newsPublisher.PublishNews("天氣日報:今天是個晴天!");
newsPublisher.PublishNews("緊急消息:交通事故發生了!");
// 解除訂閱
newsPublisher.Detach(subscriber1);
// 再次通知觀察者
newsPublisher.PublishNews("體育新聞:我們贏得了冠軍!");
Console.ReadKey();
}
}
output: