觀察者模式

1、引入

  在系統設計中,咱們經常須要設計一種消息通知的模塊,從服務器端將消息分發給客戶端。這樣的功能實現能夠有不少不一樣的方式,今天咱們來主要介紹一下設計模式中針對這種狀況的一種處理方法,也就是觀察者模式。觀察者模式又常被叫做發佈-訂閱模式,若是你曾經向移動公司訂過手機報,那就很容易理解了,就是把你的手機號註冊到移動的手機報發送大名單裏,系統就會定時給你發消息了。觀察者模式的實現有不少種不一樣形式,比較直觀的就是今天咱們本篇要介紹的 「註冊——通知」形式。首先按老規矩,咱們先來看一下標準定義。編程

  觀察者模式(Observer):定義了一種一對多的依賴關係,讓多個觀察者同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知全部觀察者對象,使它們能夠自動更新本身。設計模式

  這裏有幾個關鍵點:服務器

  1.這是一種一對多的關係多線程

  2.多個觀察者去監聽一個對象,觀察者是主動的參與的,被監聽對象應該不關心有多少個觀察者在監聽他。spa

  3.被監聽對象只管發通知,觀察者本身去處理收到通知後的處理動做。線程

  4.觀察者能夠主動註冊或者撤銷註冊,這樣就將觀察者和監聽對象隔離開來。設計

 

 

2、類圖

 

從以上類圖中咱們來總結觀察者模式中的幾個重要要素:orm

1.抽象主題:抽象的被觀察角色,定義了能夠增長或刪除觀察者的方法。通常用一個抽象類或接口實現。(不是必須的)server

2.抽象觀察者:抽象的觀察者,包含一個Update()方法,在獲得通知時更新本身。對象

3.具體主題對象:在具體的主題內部發生變化時,向觀察者發出通知。

4.具體觀察者對象:在收到主題通知時更新本身狀態。

 

3、示例代碼

 咱們來用一個比較簡單的"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 就再也收不到消息通知了。

 

4、總結

 

觀察者模式實現了抽象與具體的分離,定義了穩定的更新消息傳遞機制,使類之間各自維護本身的功能,提升系統的可重用性和可維護性。

優勢:

1.觀察者與被觀察者之間創建一個抽象的耦合關係,被觀察者(主題角色)並不知道和關心每一個一具體的觀察者,它只要關心一個共同的觀察者接口。

2.觀察者模式支持廣播通訊。

 

缺點:

若是有不少觀察者同時監聽一個主題角色對象,主題角色要花費不少時間去通知每一個觀察者。能夠考慮用多線程的方式去投遞通知。

相關文章
相關標籤/搜索