下圖是一個經典的觀察者模式的結構。(圖來源於wikipedia)

觀察者模式被定義為解決一個對象對多個對象的依賴問題。當一個對象的狀態發生改變,它會自動通知其它依賴對象。關於該設計模式的介紹可以更多參考Terrylee的.NET設計模式(19):觀察者模式(Observer Pattern)。這篇文章主要介紹在 .NET 4.0 怎么實現觀察者模式。
在.NET 4.0下位我們提供了兩個觀察者模式的底層接口:IObservable<T>和IObserver<T>。這兩個接口定義如下:
public interface IObservable<out T> { IDisposable Subscribe(IObserver observer); }
public interface IObserver<in T> { void OnCompleted(); void OnError(Exception error); void OnNext(T value); }
IObserable就相當於是傳統模式中的Subject,而IObserver就是訂閱者。現在來演示一個新聞訂閱的實例:當有被訂閱的新聞站點有新文章發布時,發送信息通知它的訂閱者。
首先定義一個Article類,它就相當於是新聞網站中每一篇文章實體,保存着每篇文章的信息:
class Article { public String Title; public DateTime Date; public String Author; public String Content; }
然后是我們的訂閱源——新聞站點:
class News : IObservable<Article> { //用一個list來模擬保存站點中所有的文章 private List<Article> articles = new List<Article>(); //保存的所有的訂閱者信息 private List<IObserver<Article>> observers = new List<IObserver<Article>>(); public IDisposable Subscribe(IObserver<Article> observer) { if (!this.observers.Contains(observer)) { this.observers.Add(observer); } return new unsubscribe(observers, observer); } private class unsubscribe : IDisposable { private IObserver<Article> _observer; private List<IObserver<Article>> _observers; public unsubscribe(List<IObserver<Article>> observers, IObserver<Article> observer) { this._observer = observer; this._observers = observers; } public void Dispose() { if (this._observers != null && this._observers.Contains(this._observer)) { this._observers.Remove(this._observer); } } } //向訂閱者發送通知 private void Notify(Article article) { foreach (var item in this.observers) { item.OnNext(article); } } //當有新的文章發布時通知訂閱者 public void AddArticle(Article article) { this.articles.Add(article); this.Notify(article); } }
下面來定義我們的訂閱者。
class Person : IObserver<Article> { //訂閱者姓名 String name; //保存訂閱的新聞站點,方便以后取消訂閱 Dictionary<IObservable<Article>, IDisposable> sbscribes = new Dictionary<IObservable<Article>, IDisposable>(); public Person(String name) { this.name = name; } public void Subscribe(IObservable<Article> news) { IDisposable unsub = news.Subscribe(this); sbscribes[news] = unsub; } public void UnSubscribe(IObservable<Article> news) { if (sbscribes.ContainsKey(news)) { sbscribes[news].Dispose(); sbscribes.Remove(news); } } //沒有實現 public void OnCompleted() { throw new NotImplementedException(); } //當訂閱中出現錯誤的處理沒有實現 public void OnError(Exception error) { throw new NotImplementedException(); } //當有新的推送通知到達后的處理 public void OnNext(Article value) { Console.WriteLine("One News: {0}",value.Title); } }
下面我們看下運行時的代碼:
static void Main(string[] args) { News ChinaNews = new News(); News EuropeNews = new News(); Person person1 = new Person("heqichang"); Person person2 = new Person("Jim"); //我自己訂閱了中國新聞和歐洲新聞 person1.Subscribe(ChinaNews); person1.Subscribe(EuropeNews); //Jim訂閱了歐洲新聞 person2.Subscribe(EuropeNews); EuropeNews.AddArticle(new Article() { Title = "New title", Date = DateTime.Now.Date, Author = "heqichang", Content = "New content" }); }
現在我們很多人都應該使用着智能手機,我們可能經常在手機上收到一些應用發來的推送信息,這樣的模式就跟我們的觀察者模式很像。
擴展閱讀:
Reactive Extensions,簡稱Rx,是以IObserable<T>以及IObserver<T>為核心的,使用LINQ方式編程的.NET擴展庫。 Rx = Observables + LINQ + Schedulers。有興趣的可以搜索一下。
以前我們訂閱博客信息,依靠的都是拉文章,現在我們也可以使用“推”的方式來訂閱。參看:PubSubHubbub
參考鏈接:
http://msdn.microsoft.com/zh-cn/library/dd783449(v=vs.100).aspx
