大家都经历够这些事情,订阅了报纸或者杂志,每当报纸杂志出新期刊的时候,不用你自己去报社去了解,邮递员都会
给你送到手上.用RSS订阅博客或是新闻,有新的博客发表或者是有新闻了,会自动送到你的邮箱中,还有使用google快
讯,google快讯会汇总你要的最新新闻,自动发送到你的邮箱里面.我们都不需去了解这些报纸杂志,新闻博客是怎么更新
的,我们第一时间回收到它们的更新内容,这些现象对应着一个设计模式,他是观察者模式!
观察者模式:又叫发布--订阅模式,定义了一种一对多的依赖关系,让多个观察则会对象同时监听某一个主题对
象.这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己.
类图:
Subject(主题),它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供
Observer(观察者)为所有的具体观察者定义一个接口,在得到主题通知时同事更新自己.
ConcretObserver(具体观察者)实际抽象观察者角色所要求的更新接口
ConcreteSubject(具体主题、具体通知者)将有关状态存入具体观察者对象,在具体主题的内部
要点:
1.主题用一个共同的接口来通知观察者
2.主题和观察者之间松耦合,主题不知道观察者的细节,只知道观察者实现了观察者的借口,
实现代码:
namespace 观察者_模式
{
/// <summary>
/// Subject类,它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供
/// 一个接口,可以增加和删除观察者对象
/// </summary>
///
abstract class Subject
{
private IList<Observer> observers = new List<Observer>();
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知观察者
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
/// <summary>
/// Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题通知时同事更新自己.
/// </summary>
///
abstract class Observer
{
public abstract void Update();
}
/// <summary>
/// ConcreteSubject类,具体主题或具体通知者,将有关状态存入具体观察者对象,在具体主题的内部
/// 状态改变时,给所有登记过的观察者发出通知
/// </summary>
///
class ConcreteSubject : Subject
{
private String SubjectState;
public string Subjectstate
{
get { return SubjectState; }
set { SubjectState = value; }
}
}
/// <summary>
/// ConcretObserver类,具体观察者,实际抽象观察者角色所要求的更新接口
/// </summary>
///
class ConcreteObserver : Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
public override void Update()
{
observerState = subject.Subjectstate;
Console.WriteLine("观察者{0}的新状态时{1}", name, observerState);
}
public ConcreteSubject Subject
{
get { return subject ; }
set { subject = value; }
}
}
class Program
{
static void Main(string[] args)
{
ConcreteSubject s = new ConcreteSubject();
s.Attach (new ConcreteObserver (s,"X"));
s.Attach (new ConcreteObserver (s,"Y"));
s.Attach (new ConcreteObserver (s,"Z"));
s.Subjectstate ="ABC";
s.Notify ();
Console .Read ();
}
}
}
特点:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性.我们不希望为了
维持一致性而使各类紧密耦合,这样会给维护,扩展和重用带来不便.而观察者模式的关键对象时主题Subject和观察者
Observer,一个Subject可以有任意数目的依赖并不需要知道谁是它的Observer,一旦Subject的状态发生了改变,所有的
Observer都可以得到通知,Subject发出通知时并不需要直达谁是它的观察者,也就是说,具体观察者是谁,它根本不需要
知道,而任何一个具体观察者不知道其他观察者的存在.
优点:
1.目标和观察者间 的松耦合,一个目标所知道的仅仅是它有一系列观察者,每个都符合抽象的Observer类的简单接
口。目标不知道任何一个观察这属于哪一个具体的类。这样目标和观察者之间的耦合是抽象的和最小的。
2.支持广播通信,主题向所有登记过的观察者发出通知。
缺点:
1.意外的更新,因为一个观察者并不知道其它观察者的存在,它可能对改变目标的最终代价一无所知。在目标上一个
看似无害的操作,可能会引起一系列对观察者以及依赖与这些观察者的那些对象的更新。此外,如果依赖准则的定义
和维护不当,常常会引起错误的更新,这种错误通常很难捕捉。
2.如果一个主题对象有很多直接或间接的观察者对象,将所有的观察这都通知会花费很多时间。
3.如果对观察者的通知是在另外的线程异步进行的话,要额外注意多线程操纵。
使用情况:
当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式.
一个抽象模型有两个方面,其中一个方面依赖于另一个方面,这时用观察者莫侯斯可以将这两者封装在独立的对象中使
它们各自独立地改变和复用.