iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
自我挑戰組

Design Pattern - 無所不在的設計模式系列 第 25

[Day25] Design Pattern - Observer觀察者模式

  • 分享至 

  • xImage
  •  

定義


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)

觀察者模式通常用在...


觀察者模式通常用於解決以下問題和情境:

  1. 物件狀態的更新通知
    當一個物件的狀態發生變化,需要通知其他物件來執行相應的操作時,可以使用觀察者模式。這樣,物件之間可以保持解耦,subject(被觀察者)只需要知道觀察者的存在,而不需要知道具體的觀察者是誰。

  2. 事件處理
    在事件驅動的程式設計中,當事件發生時,需要通知多個事件處理器或監聽器來執行相應的操作。觀察者模式可以用來實現這種事件處理機制。

  3. GUI(圖形用戶界面)
    在圖形用戶界面中,常常需要監聽用戶的操作,例如按鈕點擊、滑鼠移動等等。觀察者模式可以用於設計和實現這些事件的處理。

  4. 資料推送
    當資料源有新數據可用時,需要將數據推送給多個接收者,例如即時通訊、訊息推送等場景中,觀察者模式可以有效地實現這種資料推送機制。

觀察者模式的元素


  • 被觀察者(Subject):或是發布者(Publisher),也是被觀察的物件,它維護一個觀察者列表,可以添加、刪除和通知觀察者。

  • 觀察者(Observer):也稱訂閱者(Subscribers),等待被通知的物件,當被觀察者的狀態發生變化時,觀察者會收到通知,並執行相應的操作。

  • 具體被觀察者(Concrete Subject):主題的具體實作,它繼承自被觀察者介面並實作相關的方法。

  • 具體觀察者(Concrete Observer):觀察者的具體實作,通常實現一個更新方法,以便在接收到通知時執行特定的操作。

UML


C#實作


假設我們作一個新聞通知系統
有不同主題的新聞時,會送通知到多個訂閱者(使用者)中

首先是被觀察者(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:


上一篇
[Day24] Design Pattern - Memento備忘錄模式
下一篇
[Day26] Design Pattern - State狀態模式
系列文
Design Pattern - 無所不在的設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言