察者模式的定义
观察者模式(Observer Pattern),有时被称作发布/订阅模式(不严谨的说法),观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。观察者模式属于行为型模式。
模式结构
四种关键类:
- 抽象被观察者类:此类作为所有目标Subject的抽象基类,因为有时被观察类不止一种。所以声明此抽象类可以把所有要充当Subject的类都继承于此类.用于规划目标(即发布方)所产生的事件,及提供触发。将这个基类声明为抽象类的好处,主要是为了不能实例化该类对象,确保模式完整性。
- 具体被观察者类:继承抽象基类,并将有关状态存入具体观察者对象,当触发内部委托事件时,按顺序调用观察者订阅的方法。
- 抽象观察者类:为所有的具体观察者定义一个接口或抽象类(含有抽象方法)或普通类(含有虚方法),然后在具体观察者类实现接口或重写方法。不同的情况使用不同方法,具体情况具体分析,不能死板。
- 具体观察者:实现抽象观察者角色所要求的更新接口(覆盖方法) ,接口或方法已在观察者基类中注册于委托事件,由委托事件调度执行,不需要直接以便使本身的状态与主题状态协调。
如图解释:

注意:
根据合适的情况选择合适的定义方法,实际最少只需要两个类即可,一个观察者类和一个被观察者类,但是再开发中为了使程序更加稳定,避免Bug和以后重写的方便。选取最为合适自己的方法去实现功能,no warning,no error,no Bug,是最有效的。
观察模式的缺点
时间复杂度
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
内联不足
虽然观察者模式可以随时使观察者知道所观察的对象发送了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎样发生变化的
容易出现循环调用
如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃,在使用观察者模式应特别注意这点。
观察者模式经典猫和老鼠案例:


1 abstract class Subject//抽象被观察者类
2 {
3 protected string name;
4
5 public event Action doWhatEvent;
6
7 public Subject(string name)
8 {
9 this.name = name;
10 }
11
12 protected void doWhat()
13 {
14 if (this.doWhatEvent !=null)//保证安全性,确保事件不为空
15 {
16 this.doWhatEvent();
17 }
18 }
19 }


1 class Cat:Subject//被观察者类
2 {
3 public Cat(string name) : base(name)
4 {
5 this.name = name;
6 }
7
8 public void Cry()
9 {
10 Console.WriteLine("猫叫...");
11 this.doWhat();//调用方法
12 }
13 }


1 abstract class Observer
2 {
3 protected string name;
4 /// <summary>
5 /// 把被观察者对象的事件注册行为方法(订阅)
6 /// </summary>
7 /// <param name="name"></param>
8 /// <param name="mySubject"></param>
9 public Observer(string name,Subject mySubject)
10 {
11 this.name = name;
12 mySubject.doWhatEvent += MySubject_doWhatEvent;//注册进事件
13 }
14 public abstract void MySubject_doWhatEvent();//子类处理行为方法(如果有多个事件可以注册多个)
15 }


class SmallMouse:Observer
{
public SmallMouse(string name, Subject mySubject) : base(name, mySubject)
{
this.name = name;
}
public override void MySubject_doWhatEvent()
{
Console.WriteLine("小老鼠很惊恐,不知所措...");
}
}


1 class BigMouse:Observer
2 {
3 public BigMouse(string name, Subject mySubject) : base(name, mySubject)
4 {
5 this.name = name;
6 }
7
8 public override void MySubject_doWhatEvent()
9 {
10 Console.WriteLine("大老鼠说了一声'Fuck!',然后逃跑...");
11 }
12 }
最后Program类:


1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Cat cat = new Cat("黑猫警长");
6 BigMouse bigMouse = new BigMouse("杰瑞",cat);
7 SmallMouse smallMouse = new SmallMouse("三只耳",cat);
8
9 cat.Cry();
10 }
11 }
以下博客为我提供了帮助,表示感谢
借鉴:http://www.cnblogs.com/xmfdsh/p/4047114.html