下图是一个经典的观察者模式的结构。(图来源于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