观察者模式(Observer)定义了对象间一对多的联系。当一个对象的状态发生变化时,所有与它有联系的观察者对象都会得到通知。观察者模式将被观察的目标和观察者解耦,一个目标可以有任意多的观察者,观察者也可以观察任意多的目标,构成复杂的联系,而每个观察者都不知道其他观察者的存在。
这里我就不列出那么多正式化的UML图了,那些是书本上的事,如果要详细学设计模式,推荐Gof的大话设计模式
我们在这里举两个例子来说明
第一:烧水瓶热水时候,当烧到97度的时候,显示屏会收到消息,然后再屏幕上显示当前温度,声控器会发出声音,提示报警!
第二:某软件公司突然来了一个性感的女秘书,程序员A和程序员B这两个钓丝按耐不住了,密切注视着这位女秘书,秘书的一举一动都会影响到他们!
我们先来看第一个问题,仔细分析一下大多数人都会写出如下代码:
class Heater { private: signed int temperature; public: //热水机烧水 void BoilWater() { for(int i=0;i<=100;++i) { temperature = i; if(temperature == 97) { ShowMSG(); MakeAlert(); } } } //显示屏显示 void ShowMSG() { cout<<"谁快开了,当前温度:"<<temperature<<",别再烧了"<<endl; } //警报器发出警报 void MakeAlert() { cout<<"Alarm:嘀嘀嘀,水已经"<<temperature<<"度了"<<endl; } };
这样的设计虽然可以达到目的,但是方式不太好,我们知道也许烧水器,显示屏和警报器不一定是同一个厂家生产的,所以我们应该把他们分割成几个类,代码如下:
//烧水器(被观察者) class Heater { private: signed int temperature; public: //热水机烧水 void BoilWater() { for(int i=0;i<=100;++i) { temperature = i; if(temperature == 97) { //向监听他的两个类发出信息 } } } }; //显示屏类(观察着) class show { public: void ShowMSG(int param) { cout<<"谁快开了,当前温度:"<<param<<",别再烧了"<<endl; } }; //警报器类(观察着) class alarm { public: void MakeAlert(int param) { cout<<"Alarm:嘀嘀嘀,水已经"<<temperature<<"度了"<<endl; } }
如果像上面的设计,显示屏类和警报器类都在监督着烧水器的温度,当达到97度的时候,烧水器就会像他的两个观察着发出信息,一边执行必要的操作,可是在C++不像C#有委托和事件处理,所以在C++中需要用到多态的方式,利用vector来操作消息处理,相信这个例子已经很形象的讲述了观察者模式了,接下来让我们具体实现第二个例子
例子结构如下:
IObservable,被观察者接口
CmishuObservable,被观察者秘书
IObserver,观察者接口
CCoderBObserver,观察者程序员B
CCoderAObserver观察者程序员A
class IObservable //被观察者接口 { IObservable() {} virtual ~IObservable() {} virtual void AddObserver(IObserver *pObserver) = 0; //所有被观察者都有的操作 virtual void DeleteObserver(IObserver *pObserver) = 0; virtual void NotifyObservers(string context) = 0; }; class CmishuObservable:public IObservable //秘书继承并实现了接口的函数 { private: vector<IObserver *> m_ObserverList; //用于盛装观察者的容器 typedef vector<IObserver *>::iterator Observer_iter; public: virtual void AddObserver(IObserver *pObserver) { m_ObserverList.push_back(pObserver); //把观察者加入到容器中 } virtual void DeleteObserver(IObserver *pObserver) //删除观察着 { Observer_iter it = m_ObserverList.begin(); for(;it!= m_ObserverList.end();++it) { if(pObserver == *it) //这里有点处理得不好,不该比指针,权当例子吧 m_ObserverList.erase(it); } } virtual void NotifyObservers(string context) //通告观察者,以便执行更新 { Observer_iter it = m_ObserverList.begin(); for(;it != m_ObserverList.end();++it) (*it)->update(context); } void HaveBreakfast() //秘书的行为 { cout<<"美女秘书:开始吃饭去了,饿了啦"<<endl; this->NotifyObservers(string("开始吃饭去了,饿了啦")); } void HaveFun() //秘书的行为 { cout<<"美女秘书:人家好想去玩啊!"<<endl; this->NotifyObservers(string("人家好想去玩啊!")); } }; class IObserver //观察者接口 { public: IObserver() {} virtual ~IObserver() {}; virtual void update(string context) = 0; }; class CCoderAObserver:public IObserver //程序员A继承并实现update { private: string name; public: CCoderAObserver() { name = "Coder A"; } virtual void update(string context) { //收到消息:我好想去玩,或者去吃饭 //执行相应的操作 } }; class CCoderBObserver:public IObserver //程序员B并实现update { private: string name; public: CCoderBObserver() { name = "Coder B"; } virtual void update(string context) { //收到消息:我好想去玩,或者去吃饭 //执行相应的操作 } };
通过上面的例子 应该对观察者模式在C++中如何实现比较了解了,总结一下就是利用多态性+容器来分别调用观察者的update函数!