觀察者模式(有時又被稱爲發佈-訂閱Subscribe>模式、模型-視圖View>模式、源-收聽者Listener>模式或 從屬者模式)是軟件設計模式的一種。在此種模式中,一個目標物件管理全部相依於它的觀察者物件,而且在它自己的狀態改變時主動發出通知。這一般透過呼叫各 觀察者所提供的方法來實現。此種模式一般被用來實現事件處理系統。 html
(1)抽象主題(Subject)web
持有一個觀察者對象的集合,提供增長,刪除觀察者對象的接口,當須要關注的狀態變化時候,須要通知全部持有的觀察者對象。設計模式
(2)具體主題(Concrete Subject)數組
被觀察者的具體實現...ide
(3)抽象觀察者(Observer)post
定義一個接口,在接受通知時候更新狀態this
(4)具體觀察者(Concrete Observer)url
觀察者的具體實現...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)運行結果
優缺點
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