iT邦幫忙

2022 iThome 鐵人賽

DAY 18
1

各位應該都有在 Youtube 看過影片的經驗吧!如果想要看到影片,可以直接在 Youtube 上面搜尋關鍵字,或者在各別 Youtuber 的頻道中看到他們的影片,也可以按下訂閱按鈕,那麼未來當 Youtuber 有新影片上架時,就可以第一時間收到通知,這也是今天要討論的主題,如何透過 Observer模式去實現「訂閱並且主動通知」的功能。

Observer - 定義

定義物件間的一種一對多的相依關係,當一個物件的狀態發生改變時,所有相依於它的物件都將得到通知並自動更新。

https://ithelp.ithome.com.tw/upload/images/20220927/20136443j2NiGI5KWS.png

(圖片來源: https://www.cs.mcgill.ca/~hv/classes/CS400/01.hchen/doc/observer/observer.gif)

範例 UML

https://ithelp.ithome.com.tw/upload/images/20220927/20136443Ox6pNr5Fac.png

Code要點

  • Observer 是抽象類別,字面上是觀察者,會實作Update改寫更新時要做的事。
  • Subject 也是抽象類別,字面上是主題,也就是被觀察者,會去實現註冊訂閱者、移除訂閱者以及通知訂閱者的功能,其中會去聚合Observer,當觸發通知訂閱者的功能時,就會對聚合ObserverUpdate的呼叫。

不囉嗦上Code!

using System;
using System.Collections.Generic;

namespace DAY18_Observer
{
    public class Program
    {
        static void Main(string[] args)
        {
            // 建立 Youtuber
            Youtuber youtuber = new Youtuber("老高");

            // 訂閱者 Howard & John
            Subscriber Howard = new Subscriber("Howard");
            Subscriber John = new Subscriber("John");

            // 訂閱者訂閱 Youtuber
            youtuber.RegisterSubscriber(Howard);
            youtuber.RegisterSubscriber(John);

            Console.WriteLine("---------");

            // Youtuber上傳新影片
            youtuber.UploadNewVideo("9月份新影片");

            Console.WriteLine("---------");

            // John取消訂閱 Youtuber
            youtuber.RemoveSubscriber(John);
            youtuber.UploadNewVideo("10月份新影片");
        }
    }

    public abstract class Subject
    {
        public string Name { get; set; }
        public abstract void RegisterSubscriber(Observer observer);
        public abstract void RemoveSubscriber(Observer observer);
        public abstract void NotifyObservers();
    }

    public abstract class Observer
    {
        public string Name { get; set; }
        public abstract void Update(string content, string subjectName);
    }

    public class Youtuber : Subject
    {
        private readonly List<Observer> _observers;
        private string _content = String.Empty;

        public Youtuber(string name)
        {
            _observers = new List<Observer>();
            Name = name;
        }

        public void UploadNewVideo(string content)
        {
            _content = content;
            NotifyObservers();
        }

        public override void RegisterSubscriber(Observer observer)
        {
            _observers.Add(observer);
            Console.WriteLine($"{observer.Name}訂閱{this.Name}成功!");
        }

        public override void RemoveSubscriber(Observer observer)
        {
            _observers.Remove(_observers.Find(x => x == observer));
            Console.WriteLine($"{observer.Name}取消訂閱{this.Name}!");
        }

        public override void NotifyObservers()
        {
            _observers.ForEach(x => x.Update(_content, this.Name));
        }
    }

    public class Subscriber : Observer
    {
        public Subscriber(string name)
        {
            // Name為抽象類別共通的屬性值
            Name = name;
        }

        // Youtuber會使用NotifyObservers()方法,觸發這裡改寫的Update()通知
        public override void Update(string content, string youtuberName)
        {
            Console.WriteLine($"{Name}收到{youtuberName}最新影片的通知,內容為:{content}");
        }
    }
}
  • 結果

https://ithelp.ithome.com.tw/upload/images/20220927/20136443aOjQMazqnn.png

簡單的小結

Observer模式 (觀察者模式)主要的重點是在處理一對多的相依關係,從例子來看,Youtuber 可以去註冊很多的Subscriber,並且藉由NotifyObservers()方法就能對所有的Subscriber做到通知的功能。


上一篇
【DAY17】Double-Checked Locking模式 - 多執行序環境
下一篇
【DAY19】Object Pool模式 - 管理你的昂貴物件池
系列文
勇闖秘境!探索物件導向背後的設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言