设计模式 学习笔记(6)观察者模式
(14)观察者模式
观察者模式又叫发布-订阅模式。它定义了一种一对多的依赖关系,让多个观察着对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。就像前台秘书通知后面玩股票的同事:-)。
Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察着对象的引用保存在一个聚集里,每一个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
1 abstract class Subject 2 { 3 private IList<Observer> observers=new IList<Observer>(); 4 //增加观察者 5 public void Attach(Observer observer) 6 { 7 observers.Add(observer); 8 } 9 //移除观察者 10 public void Detach(Observer observer) 11 { 12 observers.Remove(observer); 13 } 14 //通知 15 public void Notify() 16 { 17 foreach (Observer o in observers) 18 { 19 o.Update(); 20 } 21 } 22 }
Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个Update()方法,这个方法叫做更新方法。
1 abstract class Observer 2 { 3 public abstract void Update(); 4 }
ConcreteSubject类,叫做具体主题或者具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
1 class Concrete:Subject 2 { 3 private string subjectState; 4 //具体被观察者状态 5 public string SubjectState 6 { 7 get{return subjectState;} 8 set{subjectState=value;} 9 } 10 }
ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
1 class ConcreteObserver:Observer 2 { 3 private string name; 4 private string observerState; 5 private ConcreteSubject subject; 6 7 public ConcreteObserver(ConcreteSubject subject,string name) 8 { 9 this.subject=subject; 10 this.name=name; 11 } 12 public override void Update() 13 { 14 observerState=subject.SubjectState; 15 Console.WriteLine("观察者{0}的新状态是{1}",name,oberserState); 16 } 17 public ConcreteSubject Subject 18 { 19 get{return subject;} 20 set{subject=value;} 21 } 22 }
客户端代码
1 static void Main(string[] args) 2 { 3 ConcreteSuject s=new ConcreteSubject(); 4 s.Attach(new ConcreteObserver(s,"X")); 5 s.Attach(new ConcreteObserver(s,"Y")); 6 s.Attach(new ConcreteObserver(s,"z")); 7 s.SubjectState="ABC"; 8 s.Notify(); 9 Console.Read(); 10 }
结果显示
观察者X的新状态是ABC
观察者Y的新状态是ABC
观察者Z的新状态是ABC
观察者模式的动机:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合。这样会维护、扩展和重用都带来不便。而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
当一个对象的改变需要改变其他对象的时候。而且是不知道有多少对象有待改变时。当一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。总之,观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体 。从而使得各自的变化都不会影响另一边的变化。细心地可以发现,这就是依赖倒转原则的最佳体现。
现实编程中,具体的观察者完全有可能是风马牛不相及的类,但它们都需要根据通知者的通知来做出Update()的操作,所以让它们都实现下面这样一个接口就可以实现这个想法了。
1 interface Observer 2 { 3 void Update(); 4 }
事件委托说明
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的'类',委托的实例将代表一个具体的函数。委托就是'类'。
delegate void EventHandler();可以理解为声明了一个特殊的'类'。而'public EventHandler Upadate;'可以理解为声明了一个'类'的变量。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。而且,一个委托可以搭载多个方法,所有方法被依次唤起,它可以使得委托对象所搭载的方法并不需要属于同一个类。委托对象所搭载的所有方法必须具有相同的参数列表和返回值。