// 宣告委派
public delegate void DelNotify(Publisher publisher, News news);
#region 報社
public class Publisher {
public Publisher() { }
public Publisher(string pName) {
Name = pName;
}
public string Name;
// 建立委派
//public DelNotify delNotifyBreakingNews;
// 避免被外部亂呼叫加上 event 關鍵字
public event DelNotify delNotifyBreakingNews;
// 可直接用定義好的委派 EventHandler
public event EventHandler eveNotifyBreakingNews;
public event EventHandler eveNotifyStockNews;
#region 發佈最新消息
public void PublishBreakingNews(string pNews) {
News news = new News() {
title = "最新消息",
content = pNews
};
// 呼叫委派執行工作
//delNotifyBreakingNews.Invoke(pNews);
// 避免上一行沒訂閱者時 Invoke 會報錯,多包一個檢查的方法呼叫
OnGetNews(this, news, delNotifyBreakingNews);
OnGetNews(this, news, eveNotifyBreakingNews);
}
#endregion
#region 發佈股市消息
public void PublishStockNews(string pNews) {
News news = new News() {
title = "股市消息",
content = pNews
};
OnGetNews(this, news, eveNotifyStockNews);
}
#endregion
#region 發佈消息時檢查委派並執行
/// <summary> 發佈消息時檢查委派並執行 </summary>
protected void OnGetNews(Publisher pPublisher, News pNews, DelNotify del) {
// 檢查有訂閱者才 Invoke
//if (delNotifyBreakingNews != null) {
// delNotifyBreakingNews.Invoke(pNews);
//}
del?.Invoke(pPublisher, pNews);
}
/// <summary> 發佈消息時檢查委派並執行 </summary>
protected void OnGetNews(Publisher pPublisher, News pNews, EventHandler del) {
del?.Invoke(pPublisher, pNews);
}
#endregion
}
#endregion
#region 新聞
public class News : EventArgs {
public string title;
public string content;
}
#endregion
#region 訂閱者
class Subscriber {
public Subscriber() { }
public Subscriber(string pName) {
Name = pName;
}
public string Name;
public void NotifyMe(Publisher pPublisher, News pNews) {
Console.WriteLine($"我是 {Name},我已經收到來自{pPublisher.Name}的{pNews.title}:{pNews.content}");
}
//用定義好的 EventHandler 要自己轉型
public void NotifyMe(object sender, EventArgs eventArgs) {
Publisher publisher = sender as Publisher;
News news = eventArgs as News;
Console.WriteLine($"我是 {Name},我已經收到來自{publisher.Name}的{news.title}:{news.content}");
}
}
#endregion
class Program {
static void Main(string[] args) {
// 產生報社
Publisher AppleNews = new Publisher("蘋果日報");
Publisher BananaNews = new Publisher("香蕉日報");
// 產生訂閱者
Subscriber Tom = new Subscriber("Tom");
Subscriber John = new Subscriber("John");
Subscriber Mary = new Subscriber("Mary");
Subscriber Lisa = new Subscriber("Lisa");
// 訂閱即時新聞(報社的委派指定訂閱者的 NotifyMe 方法)
AppleNews.delNotifyBreakingNews += Tom.NotifyMe;
AppleNews.delNotifyBreakingNews += John.NotifyMe;
AppleNews.eveNotifyBreakingNews += Tom.NotifyMe;
AppleNews.eveNotifyBreakingNews += John.NotifyMe;
AppleNews.eveNotifyStockNews += Mary.NotifyMe;
AppleNews.eveNotifyStockNews += Lisa.NotifyMe;
BananaNews.eveNotifyBreakingNews += Mary.NotifyMe;
BananaNews.eveNotifyBreakingNews += Lisa.NotifyMe;
BananaNews.eveNotifyStockNews += Tom.NotifyMe;
BananaNews.eveNotifyStockNews += John.NotifyMe;
// 委派要能讓客戶訂閱,就要能被外部使用,但委派可能被外部執行而產生意料之外的事。
// 比如外部 Invoke 傳入假消息,訂閱者都會收到通知。
// 解決方法是在定義委派型別前加上 event,C# 編譯器就會禁止外部來執行這個委派。
//AppleNews.delNotifyBreakingNews.Invoke(AppleNews, new News() { title = "假消息", content = "牽手會懷孕" });
//發送新聞時就會呼叫委派執行發送訂閱的事件
AppleNews.PublishBreakingNews("發生六級地震!!");
AppleNews.PublishStockNews("美股大漲!!");
BananaNews.PublishBreakingNews("發現 COVID-19 變種!!");
BananaNews.PublishStockNews("台股開高走低!!");
}
}
參考來源
https://ithelp.ithome.com.tw/articles/10228852
https://ithelp.ithome.com.tw/articles/10228906