观察者模式又叫做发布-订阅(Publish - Subscribe)模式,模型-视图(Model - View)模式、源-监听器(Source - Listener)模式,依赖(Dependents)模式。
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并被自动更新。
这一模式中的关键对象是目标(subject)和观察者(observer)。一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有观察者都得到通知。作为对这个通知的响应,每个观察者都将查询目标以使其状态与目标的状态同步。
这种交互也称为发布-订阅。目标是通知的发布者。它发出通知时并不需知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。
Observer模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制。
其缺点是每个外观对象必须继承这个抽象出来的观察者接口类。虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
Subject(目标): 把所有观察者对象的引用保存在一个聚集里,每个subject可以有任意数量的观察者;提供注册和删除观察者对象的接口。
Observer(观察者): 为所有的具体观察者定义一个接口;在得到subject的通知时更新自己;
ConcreteSubject(具体目标): 将有关状态存入具体观察者对象;在具体目标的内部状态改变时,给所有登记过的观察者发出通知。
ConcreteObserver(具体观察者):维护一个指向ConcreteSubject对象的引用;存储有关状态,这些状态应与目标的状态保持一致;实现Observer的更新接口。
// Observer pattern -- Structural example using System; using System.Collections; // "Subject" abstract class Subject { // Fields private ArrayList observers = new ArrayList(); // Methods 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(); } } // "ConcreteSubject" class ConcreteSubject : Subject { // Fields private string subjectState; // Properties public string SubjectState { get{ return subjectState; } set{ subjectState = value; } } } // "Observer" abstract class Observer { // Methods abstract public void Update(); } // "ConcreteObserver" class ConcreteObserver : Observer { // Fields private string name; private string observerState; private ConcreteSubject subject; // Constructors public ConcreteObserver( ConcreteSubject subject, string name ) { this.subject = subject; this.name = name; } // Methods override public void Update() { observerState = subject.SubjectState; Console.WriteLine( "Observer {0}'s new state is {1}", name, observerState ); } // Properties public ConcreteSubject Subject { get { return subject; } set { subject = value; } } } /// <summary> /// Client test /// </summary> public class Client { public static void Main( string[] args ) { // Configure Observer structure ConcreteSubject s = new ConcreteSubject(); s.Attach( new ConcreteObserver( s, "1" ) ); s.Attach( new ConcreteObserver( s, "2" ) ); s.Attach( new ConcreteObserver( s, "3" ) ); // Change subject and notify observers s.SubjectState = "ABC"; s.Notify(); } }