介绍
定义
观察者模式又叫做发布-订阅模式,模型-视图模式。
观察者模式属于行为型模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
理解
观察者模式完美的将观察者和被观察的对象分离开。举个常见的例子,前阵子由于总是突发性高烧去医院检查,肯定得排队哈,不能隔两分钟就去问大夫“轮到我了吗?”,而是坐在门口等候大夫的通知,大家都接收到一个名字的信号,叫谁谁去。在这其中,大夫手里的名单就是被观察者,每一个病人就是一个观察者。
结构图
举例实现
通知者接口
//通知者接口
interface Subject
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
具体的通知者类
//具体的通知者(病人名单)这只是其中一个通知的方法,也可以实现其他的方法,所有可以让此实现通知者接口
class Roster:Subject
{
//病人
private IList<Observer> observers = new List<Observer>();
private string action;
//增加
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();
}
//名单状态,看看叫到哪个名字了
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
具体的观察者
//抽象观察者
abstract class Observer
{
protected string name;
protected Subject sub;
public Observer (string name,Subject sub) //抽象通知者,代替具体通知者对象
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
等候检查的同志 //检查身体的病人
class Patient:Observer
{
public Patient (string name,Subject sub):base(name ,sub ) //抽象通知者取代具体通知者Subject sub
{
}
public override void Update()
{
Console.WriteLine("{0} {1}来病房进行检查!", sub.SubjectState, name); //抽象通知者状态代替可能出现的具体通知状态,如病人名单
}
}
客户端代码:
static void Main(string[] args)
{
//金秀贤名字通知
Roster mingdan= new Roster();
//等待中的金秀贤
Patient bingren1 = new Patient("金秀贤", mingdan);
mingdan.Attach(bingren1);
//通知到
mingdan.SubjectState = "金秀贤同志!";
//发出通知
mingdan.Notify();
}
通知病人也有通知不到的时候,或许没有在,也或者声音小,没有注意听。其实结果一样,代码如下
static void Main(string[] args)
{
//金秀贤名字通知
Roster mingdan= new Roster();
//等待中的金秀贤
Patient bingren1 = new Patient("金秀贤", mingdan);
//等待中的淑敏君
Patient bingren2 = new Patient("淑敏君", mingdan);
mingdan.Attach(bingren1);
mingdan.Attach(bingren2);
mingdan.Detach(bingren2); //没有被通知到
//通知到
mingdan.SubjectState = "金秀贤同志!";
//发出通知
mingdan.Notify();
}
}
结果显示:
事件委托
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的”类“,委托的实例将代表一个具体的函数。就如上边的例子,或许有的医院并没有那么正规,只是病房里没有病人了,就会叫外边的根据不同的病情进入病房,叫病人的方法也可以由好多种方法,为了处理这些方法的类,用到了委托。
代码如下:
声明一个委托,名称叫”EventHandler“,无参数,无返回值。
delegate void EventHandler();
类的区分:(在此只写了一个名单通知的类)
class Roster : Subject
{
//声明一事件Update,类型为委托EventHandler
public event EventHandler Update; //声明一“EventHandler"的委托事件,名称叫Update
private string action;
//通知
public void Notify()
{
Update();
}
//名单状态,看看叫到哪个名字了
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
客户端重要代码:
//金秀贤名字通知
Roster mingdan = new Roster();
//等待中的金秀贤
PatientHeadache bingren1 = new PatientHeadache("金秀贤", mingdan);
//等待中的淑敏君
PatientHaveFever bingren2 = new PatientHaveFever("淑敏君", mingdan);
mingdan.Update += new EventHandler(bingren1.IntoHeadache);
mingdan.Update += new EventHandler(bingren2.IntoHaveFever);
//将看“头痛的病人”和看“发烧的病人”和“分别进入病房的方法”都挂钩到“名单”的“更新”上了,也就是将量不同类的不同方法委托给名单类的“更新”了
//通知到
mingdan.SubjectState = "病人名单通知:";
//发出通知
mingdan.Notify();
实现结果:结果出来了,委托与事件的机制几乎消除了这两个模块之间的耦合,灵活性提高了很多。如果需要增加观察者,则只需要覆盖基类抽象方法及把观察目标传递给基类。委托和事件处理事情的能力真的是令人佩服啊!
好处总结
观察者模式最终所达到的效果就是实现了“高内聚,低耦合“,所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。