下图是一个经典的观察者模式的结构。(图来源于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
2 Comments
#1 sdj @ 2012-09-07 14:59
原来如此。
Qichang He @ 2012-09-15 11:13
欢迎来访!