在系統設計中,咱們經常須要設計一種消息通知的模塊,從服務器端將消息分發給客戶端。這樣的功能實現能夠有不少不一樣的方式,今天咱們來主要介紹一下設計模式中針對這種狀況的一種處理方法,也就是觀察者模式。觀察者模式又常被叫做發佈-訂閱模式,若是你曾經向移動公司訂過手機報,那就很容易理解了,就是把你的手機號註冊到移動的手機報發送大名單裏,系統就會定時給你發消息了。觀察者模式的實現有不少種不一樣形式,比較直觀的就是今天咱們本篇要介紹的 「註冊——通知」形式。首先按老規矩,咱們先來看一下標準定義。編程
觀察者模式(Observer):定義了一種一對多的依賴關係,讓多個觀察者同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知全部觀察者對象,使它們能夠自動更新本身。設計模式
這裏有幾個關鍵點:服務器
1.這是一種一對多的關係多線程
2.多個觀察者去監聽一個對象,觀察者是主動的參與的,被監聽對象應該不關心有多少個觀察者在監聽他。spa
3.被監聽對象只管發通知,觀察者本身去處理收到通知後的處理動做。線程
4.觀察者能夠主動註冊或者撤銷註冊,這樣就將觀察者和監聽對象隔離開來。設計
從以上類圖中咱們來總結觀察者模式中的幾個重要要素:orm
1.抽象主題:抽象的被觀察角色,定義了能夠增長或刪除觀察者的方法。通常用一個抽象類或接口實現。(不是必須的)server
2.抽象觀察者:抽象的觀察者,包含一個Update()方法,在獲得通知時更新本身。對象
3.具體主題對象:在具體的主題內部發生變化時,向觀察者發出通知。
4.具體觀察者對象:在收到主題通知時更新本身狀態。
咱們來用一個比較簡單的"Server——Client"消息推送的例子來認識一下觀察者模式的使用過程。
1.首先須要定義一個抽象的客戶端接口,服務器只須要和接口打交道。這樣遵照了「面向接口編程,而非面向實現編程」的OO原則
1 /// <summary> 2 /// 客戶端抽象接口 3 /// </summary> 4 public interface IClient 5 { 6 void Notification(string message); 7 }
2.具體的客戶端實現,每一個客戶端必須實現用於接收通知並顯示通知的 Notification()方法
1 /// <summary> 2 /// 客戶端A 3 /// </summary> 4 public class ClientA : IClient 5 { 6 //用於顯示接收到消息的方法 7 public void Notification(string message) 8 { 9 Console.WriteLine(string.Format("This is Client A. \n New Message Received:{0} ",message)); 10 } 11 } 12 /// <summary> 13 /// 客戶端B 14 /// </summary> 15 public class ClientB:IClient 16 { 17 public void Notification(string message) 18 { 19 Console.WriteLine(string.Format("This is Client B. \n New Message Received:{0}", message)); 20 } 21 } 22 /// <summary> 23 /// 客戶端C 24 /// </summary> 25 public class ClientC:IClient 26 { 27 public void Notification(string message) 28 { 29 Console.WriteLine(string.Format("This is Client C. \n New Message Received:{0}", message)); 30 } 31 }
3.服務端的實現,運用了委託和事件來處理與客戶端的消息發送
1 /// <summary> 2 /// 服務器 3 /// </summary> 4 public class Server 5 { 6 //負責發送消息的委託和事件 7 //客戶端只要將接收消息的方法綁定在這個事件上就能夠獲得新消息 8 public delegate void SendMessageHandler(string msg); 9 10 public static event SendMessageHandler SendMessageEvent; 11 12 //執行消息發送的方法 13 public static void Notify() 14 { 15 if(SendMessageEvent!=null) 16 { 17 SendMessageEvent(Message); 18 } 19 } 20 21 public static string Message; 22 }
4. 調用示例,服務器向全部客戶端發送消息通知。
1 static void Main(string[] args) 2 { 3 //將須要發送通知的客戶端集中放到一個列表中管理 4 IList<IClient> ClientList=new List<IClient>(); 5 ClientList.Add(new ClientA()); 6 ClientList.Add(new ClientB()); 7 ClientList.Add(new ClientC()); 8 //將全部客戶端的接收消息方法註冊到服務器的發送事件上 9 foreach (var client in ClientList) 10 { 11 Server.SendMessageEvent += client.Notification; 12 } 13 //定義服務器要發送的消息內容 14 Server.Message = "You got a message from Server!"; 15 //開始執行發送 16 Server.Notify(); 17 Console.ReadKey(); 18 19 }
5.運行結果
一樣,客戶端也能夠撤銷消息的通知事件,咱們把調用方法稍做修改,以下
1 static void Main(string[] args) 2 { 3 //建立三個客戶端對象 4 ClientA clientA=new ClientA(); 5 ClientB clientB=new ClientB(); 6 ClientC clientC=new ClientC(); 7 8 //分別爲每一個客戶端註冊消息事件 9 Server.SendMessageEvent += clientA.Notification; 10 Server.SendMessageEvent += clientB.Notification; 11 Server.SendMessageEvent += clientC.Notification; 12 13 Server.Message = "You got a message from Server!"; 14 Server.Notify(); 15 16 //客戶端C取消接收消息通知 17 Console.WriteLine("---------------------- Client C Ignore The Message ---------------------------"); 18 Server.SendMessageEvent -= clientC.Notification; 19 20 Server.Message = "Client C has gone."; 21 Server.Notify(); 22 23 Console.ReadKey(); 24 25 }
運行結果:
取消註冊後,Client C 就再也收不到消息通知了。
觀察者模式實現了抽象與具體的分離,定義了穩定的更新消息傳遞機制,使類之間各自維護本身的功能,提升系統的可重用性和可維護性。
優勢:
1.觀察者與被觀察者之間創建一個抽象的耦合關係,被觀察者(主題角色)並不知道和關心每一個一具體的觀察者,它只要關心一個共同的觀察者接口。
2.觀察者模式支持廣播通訊。
缺點:
若是有不少觀察者同時監聽一個主題角色對象,主題角色要花費不少時間去通知每一個觀察者。能夠考慮用多線程的方式去投遞通知。