【轉】設計模式-觀察者模式 設計模式-觀察者模式

設計模式-觀察者模式

定義

觀察者模式(有時又被稱爲發佈-訂閱Subscribe>模式、模型-視圖View>模式、源-收聽者Listener>模式或 從屬者模式)是軟件設計模式的一種。在此種模式中,一個目標物件管理全部相依於它的觀察者物件,而且在它自己的狀態改變時主動發出通知。這一般透過呼叫各 觀察者所提供的方法來實現。此種模式一般被用來實現事件處理系統。 html

基本簡介

觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。舉個例子,用戶界面能夠做爲一個觀察者,業務 數據是被觀察者,用戶界面觀察業務數據的變化,發現數據變化後,就顯示在界面上。面向對象設計的一個原則是:系統中的每一個類將重點放在某一個功能上,而不 是其餘方面。一個對象只作一件事情,而且將他作好。觀察者模式在模塊之間劃定了清晰的界限,提升了應用程序的可維護性和重用性。
觀察者設計模式定義了對象間的一種一對多的依賴關係,以便一個對象的狀態發生變化時,全部依賴於它的對象都獲得通知並自動刷新。
 

(1)抽象主題(Subject)web

 持有一個觀察者對象的集合,提供增長,刪除觀察者對象的接口,當須要關注的狀態變化時候,須要通知全部持有的觀察者對象。設計模式

(2)具體主題(Concrete Subject數組

 被觀察者的具體實現...ide

(3)抽象觀察者(Observerpost

 定義一個接口,在接受通知時候更新狀態this

(4)具體觀察者Concrete Observerurl

 觀察者的具體實現...spa

 

UML圖設計

 

示例

 (1.1)抽象主題類Subject

複製代碼
    /// <summary> /// 抽象主題 /// </summary> public abstract class Subject { /// <summary> /// 全部觀察者對象 /// </summary> private List<Observer> observers = new List<Observer>(); /// <summary> /// 增長觀察者對象 /// </summary> /// <param name="observer"></param> public void AddObserver(Observer observer) { observers.Add(observer); } /// <summary> /// 移除觀察者對象 /// </summary> /// <param name="observer"></param> public void RemoveObserver(Observer observer) { observers.Remove(observer); } /// <summary> /// 發送通知 /// </summary> public void Notify() { foreach (var ob in observers) { ob.Update(); } } }
複製代碼

(1.2)具體主題類ConcreteSubject

複製代碼
    /// <summary> /// 具體通知者 /// </summary> public class ConcreteSubject : Subject { /// <summary> /// 具體觀察者狀態 /// </summary> public string SubjectState { get; set; } }
複製代碼

(1.3)抽象觀察者類

複製代碼
   /// <summary> /// 觀察者類 /// </summary> public abstract class Observer { public abstract void Update(); }
複製代碼

(1.4)具體觀察者類

複製代碼
    /// <summary> /// 具體觀察者 /// </summary> public class ConcreteObserver : Observer { public string observerState { get; set; } public string Name { get; set; } public ConcreteSubject subjcSubject { get; set; } public ConcreteObserver(ConcreteSubject subject, string name) { this.Name = name; this.subjcSubject = subject; } public override void Update() { observerState = subjcSubject.SubjectState; System.Console.WriteLine("the observer's state of {0} is {1}", Name, observerState); } }
複製代碼

(1.5)控制檯調用

複製代碼
    class Program { static void Main(string[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.AddObserver(new ConcreteObserver(subject, "ObA")); subject.AddObserver(new ConcreteObserver(subject, "ObB")); subject.AddObserver(new ConcreteObserver(subject, "ObC")); subject.SubjectState = "Ready"; subject.Notify(); System.Console.ReadKey(); } }
複製代碼

(1.6)運行結果

 

優缺點

優勢:
一、 Subject和Observer之間是鬆耦合的,分別能夠各自獨立改變。
二、 Subject在發送廣播通知的時候,無須指定具體的Observer,Observer能夠本身決定是否要訂閱Subject的通知。
三、 遵照大部分GRASP原則和經常使用設計原則,高內聚、低耦合。
缺陷:
一、  依賴關係並未徹底解除,抽象通知者依舊依賴抽象的觀察者。
二、 若是一個Subject被大量Observer訂閱的話,在廣播通知的時候可能會有效率問題。
 
思考:抽象已經下降Subject和Observer之間的耦合度,可是他們之間依舊存在依賴。而咱們觀察者模式一 定程度上注重着對觀察者的通知,也就是動做的傳遞,目前Subject中依靠維持抽象具體觀察對象,在發送通知時候循環每一個具體觀察者,調用通知方法,那 麼最終咱們的目的就是主題能調用相應的通知方法。換個角度說咱們是否是能夠維護一個方法列表,那麼C#中的委託(多播委託)彷佛能夠實現咱們的這一目標。

 

C#委託改版

咱們以一個主題通知發送消息的例子來演示

(1.1)抽象主題

複製代碼
    /// <summary> /// 抽象主題 /// </summary> public interface ISubject { void Notify(); }
複製代碼

(1.2)聲明委託和具體主題

複製代碼
    /// <summary> /// 聲明委託 /// </summary> public delegate void MsgEvent(); /// <summary> /// 具體主題 /// </summary> public class ConcreteSubject : ISubject { /// <summary> /// 定義委託事件 /// </summary> public event MsgEvent MsgAction; /// <summary> /// 執行通知 /// </summary> public void Notify() { if (MsgAction != null) MsgAction(); } }
複製代碼

(1.3)添加具體觀察者 站內信,郵件,短信

複製代碼
    /// <summary> /// 站內信 /// </summary> public class InsideLetterMsg { /// <summary> /// 發送站內信 /// </summary> public void SendInsideLetterMsg() { Console.WriteLine("發送站內信....."); } } /// <summary> /// 郵件 /// </summary> public class MailMsg { /// <summary> /// 發送郵件 /// </summary> public void SendMailMsg() { Console.WriteLine("發送郵件....."); } } /// <summary> /// 短信 /// </summary> public class SMSMsg { /// <summary> /// 發送短信 /// </summary> public void SendSMSMsg() { Console.WriteLine("發送短信....."); } }
複製代碼

(1.4)客戶端調用

複製代碼
    class Program { static void Main(string[] args) { ConcreteSubject subject = new ConcreteSubject(); //註冊事件 subject.MsgAction += (new InsideLetterMsg()).SendInsideLetterMsg; //站內信 subject.MsgAction += (new MailMsg()).SendMailMsg; //郵件 subject.MsgAction += (new SMSMsg()).SendSMSMsg; //短信 //開始發送消息了  subject.Notify(); Console.ReadKey(); } }
複製代碼

(1.5)結果

 

這個例子咱們更多關注的是行爲,主題對於觀察者行爲的執行和通知。咱們只須要在調用的時候將觀察者的方法註冊到主題中便可。省去了主題須要維護觀察者對象,循環調用觀察者對象方法的過程。順帶咱們也看一下咱們建立的委託具體是what?

 

委託看一看

(1.1)看圖說話

(1.2)System.MulticastDelegate

  

   _invocationList一般這個字段爲null,當咱們構造一個委託鏈是,他能夠引用一個委託數組,也就是說咱們給委託+=方法時候,實際是操做它.

   咱們能夠推斷出當咱們調用委託方法時候,代碼大體是這樣的(下面代碼不是可運行的代碼,只是預估大概的邏輯,僅供觀看),不知道在觀察者這塊順帶寫了下委託是否是有點

   跑偏,委託這裏只是順帶提一下,更多的知識面確定沒涉及到,只是幫助你們理解下.

複製代碼
            //從委託鏈中獲取 Delegate[] deleagetset = _invocationList as Delegate[]; if (deleagetset != null) { foreach (MsgAction m in deleagetset) { m(value); //調用每一個委託  } } else { //當前不是委託鏈 直接 invoke  _methodPtr.Invoke(_target, value); }
複製代碼

 上邊的例子只是單純的循環,中途有一個調用委託失敗都沒有健壯的處理,因此MulticastDelegate類提供了另外一個實例方法GetInvocationList,用於顯示調用鏈中的每個委託,具體你們能夠查閱相關資料。That's all!

 

文章代碼連接http://files.cnblogs.com/files/mongo/BlogObserver.zip

相關文章
相關標籤/搜索