定义:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个通知对象。当这个通知对象状态发生改变时,会告知它的所有观察者对象自动更新,进而做出相应的反映。
举个例子:
在一个班级里,自习课的时候我们偷偷看小说,这时候又很害怕老师突然来了,于是我们总是让坐窗户边没有看小说也没看书的班长替我们看着,老师来了就通知我们这些看小说的同学。然后我们就赶紧收起小说,假装在认真学习的样子。这就相当于是一个观察者模式,其中,班长相当于通知者,我们这些看小说的同学相当于是观察者,班长(通知者)发现老师来了,就通知我们(观察者)所有看小说的人,然后我们分别执行自己的处理方法(藏小说、或者扔给同桌)
实际应用:
例如在我们的VS软件中,点击运行以后,会有好几个控件跟着做出反映,比如命令窗口打开、工具箱隐藏等,这就是一个观察者模式 (还可以借助委托和事件机制来解决通知者类对观察者类的依赖)
结构图:
示例代码:
//以《大话设计模式》中的前台(通知者)、员工(观察者)之间的消息通知机制为例,只不过这里是用C++写的,而书中是用C#写的
#include<iostream>
#include<string>
#include<list>
using namespace std;
class Subject;
/****************************观察者***************************/
class Observer{
public:
Observer(string name, Subject* Sub) :name(name), Sub(Sub){ }
virtual ~Observer(){ }
virtual void update()=0; //观察者收到通知者状态信息改变以后需要做的响应函数
protected:
string name;
Subject* Sub; //观察者类有一个指向通知者的指针,用以调用通知者类里的状态改变信息接口,总要知道发生了什么吧
};
//看股票的观察者们
class StockObserver :public Observer{
public:
StockObserver(string name, Subject* Sub) :Observer(name, Sub){ }
~StockObserver(){ }
void update();
};
//玩游戏的观察者们
class GameObserver :public Observer{
public:
GameObserver(string name, Subject* Sub) :Observer(name, Sub){ }
~GameObserver(){ }
void update();
};
//看球赛的观察者们
class NBAObserver :public Observer{
public:
NBAObserver(string name, Subject* Sub) :Observer(name, Sub){ }
~NBAObserver(){ }
void update();
};
/****************************通知者***************************/
class Subject{
public:
Subject() { }
virtual ~Subject(){ }
virtual void Attach(Observer* observer) = 0; //将观察者加入到自己的名单里,当状态改变以后只会通知在自己名单里的观察者们
virtual void Detach(Observer* observer) = 0; //将观察者从自己的名单里删除
virtual void Notify() = 0; //通知函数,通知观察者们做出响应
string action;
};
class Scretary :public Subject{
public:
Scretary(){ }
~Scretary(){ }
void Attach(Observer* observer);
void Detach(Observer* observer);
void Notify();
private:
list<Observer* > observers; //用于保存需要通知的观察者们的指针,不能是对象,想想为什么
};
void Scretary::Attach(Observer* observer){
observers.push_back(observer);
}
void Scretary::Detach(Observer* observer){
observers.remove(observer);
}
void Scretary::Notify(){
list<Observer* >::iterator iter = observers.begin();
while (iter != observers.end()){
(*iter)->update(); //回调
++iter;
}
}
//注,以下这一部分必须写在上述通知者代码之后,不然会报错:使用了未定义类型Subject
void StockObserver::update(){
cout << name << "收到消息:" << Sub->action << endl;
if (Sub->action == "老板来了")
cout << "关闭股票页面" << endl;
}
void GameObserver::update(){
cout << name << "收到消息:" << Sub->action << endl;
if (Sub->action == "老板来了")
cout << "关闭游戏页面" << endl;
}
void NBAObserver::update(){
cout << name << "收到消息:" << Sub->action << endl;
if (Sub->action == "老板来了")
cout << "关闭游戏页面" << endl;
}
int main(){
Subject* Sub = new Scretary(); //创建通知者
/************创建观察者**********************************/
Observer* ob1 = new StockObserver("zhangsan", Sub);
Observer* ob2 = new NBAObserver("lisi", Sub);
Observer* ob3 = new GameObserver("wang", Sub);
/*************将指向观察者的指针加入到通知者的通知名单里(不然怎么知道通知谁呢)*******/
Sub->Attach(ob1);
Sub->Attach(ob2);
Sub->Attach(ob3);
Sub->action = "老板来了"; //发现事件发生,即状态改变
Sub->Notify(); //通知观察者们
Sub->action = "吃饭了";
Sub->Notify();
Sub->Detach(ob2); //将ob2这个观察者从自己的通知名单里移除,之后将不会通知到他
Sub->action = "老板又来了";
Sub->Notify();
return 0;
}
运行结果:
涉及到的概念:继承、抽象类、纯虚函数、动态绑定、链表list
参考书籍:《大话设计模式》