一、观察者模式引入
观察者模式(Observer 模式)应该可以说是应用多、影响广的模式之一,因为 Observer 的一个实例 Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义,MVC实现了业务逻辑和表示层的解耦。 Observer 模式也是软件开发过程中必须要掌和使用的模式之一。
Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这这“一”的多也能够同步改变。常见的一个例子就是:对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer 模式就是解决了这一个问题。
二、实现
观察者模式分为两个角色:观察者和监听者
观察者:
1.通知对于该事件感兴趣的监听者去处理
2.注册
监听者:处理事件
观察者模式典型的结构图为:
这里的目标 Subject (事件)提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。观察者 Observer 则提供一个 Update 操作,注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 事件目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。
观察者模式的使用场景:
1、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。可将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;
2、当一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;
3、当一个对象必须通知其他对象,而它又不能假定其它对象是谁,即这些对像都是松耦合的。
示例代码如下:
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
class Listener
{
public:
Listener(string name):mname(name){}
virtual void handleMessage(int message)const=0;
protected:
string mname;
};
class Listener1:public Listener
{
public:
Listener1(string name):Listener(name){}
virtual void handleMessage(int message)const
{
switch(message)
{
case 1:
cout<<mname<<" has been solved 1 message!"<<endl;
break;
case 2:
cout<<mname<<" has been solved 2 message!"<<endl;
break;
default:
cout<<mname<<"no interested this message!"<<endl;
break;
}
}
};
class Listener2:public Listener
{
public:
Listener2(string name):Listener(name){}
virtual void handleMessage(int message)const
{
switch(message)
{
case 2:
cout<<mname<<" has been solved 2 message!"<<endl;
break;
case 3:
cout<<mname<<" has been solved 3 message!"<<endl;
break;
default:
cout<<mname<<"no interested this message!"<<endl;
break;
}
}
};
class Listener3:public Listener
{
public:
Listener3(string name):Listener(name){}
virtual void handleMessage(int message)const
{
switch(message)
{
case 1:
cout<<mname<<" has been solved 1 message!"<<endl;
break;
case 3:
cout<<mname<<" has been solved 3 message!"<<endl;
break;
default:
cout<<mname<<" no interested this message!"<<endl;
break;
}
}
};
class Observe
{
public:
typedef map<int,vector<const Listener*>> _Mty;//一个事件对应一组监听者集合
typedef vector<const Listener*> _Vty;
void notify(int message)
{
_Mty::iterator fit=mymap.find(message);
if(fit!=mymap.end())
{
_Vty::iterator it=fit->second.begin();
while(it!=fit->second.end())
{
(*it)->handleMessage(message);
it++;
}
}
}
void registerMessage(int message,const Listener* pls)//注册事件及其监听者
{
_Mty::iterator fit=mymap.find(message);
if(fit != mymap.end())
{
fit->second.push_back(pls);
}
else
{
_Vty vec;
vec.push_back(pls);
mymap[message]=vec;
}
}
private:
map<int,vector<const Listener*>>mymap;
};
int main()
{
Listener1 l1("listener1");
Listener2 l2("listener2");
Listener3 l3("listener3");//生成三个监听者对象
Observe ob;
ob.registerMessage(1,&l1);//注册监听者及其对应感兴趣的事件
ob.registerMessage(2,&l1);
ob.registerMessage(2,&l2);
ob.registerMessage(3,&l2);
ob.registerMessage(1,&l3);
ob.registerMessage(3,&l3);
ob.notify(1);//传入事件1,根据上述注册,需要调动l1和l2去处理事件1
return 0;
}
上述代码中的Observe就是我们的观察者用来观察事件,当有事件到来的时候,观察者将事件下发给对该事件感兴趣的监听者,监听者对这一事件进行处理。
三、老板与员工
老板在的时候,员工们工作,老板走了,员工们娱乐
#include<iostream>
#include<list>
using namespace std;
class Observer;
class Subject {//抽象目标
virtual void Attach(Observer*) = 0;//附加观察者
virtual void Detach(Observer*) = 0;//移除观察者
virtual void Notify() = 0;//通知观察者
};
class Boss:public Subject {//目标实体
bool strat;
std::list<Observer*> mol;
public:
Boss():strat(false){}
void Attach(Observer* po);
void Detach(Observer* po);
void Notify();
void set(bool s) {
strat = s;
}
};
class Observer {//抽象观察者
public:
virtual void updata(bool) = 0;
};
class Employee:public Observer {//观察者1
Subject* mps;
public:
Employee(Subject* ps):mps(ps) {}
void updata(bool val) {
val ? cout << "员工工作" << endl : cout << "员工炒股" << endl;
}
};
class Dirver :public Observer {//观察者2
Subject* mps;
public:
Dirver(Subject* ps):mps(ps){}
void updata(bool val) {
val ? cout << "司机擦车" << endl : cout << "司机打牌" << endl;
}
};
class Reception:public Observer {//观察者3
Subject* mps;
public:
Reception(Subject* ps):mps(ps){}
void updata(bool val) {
val ? cout << "前台服务顾客" << endl : cout << "前台化妆" << endl;
}
};
void Boss::Attach(Observer* po) {
mol.push_back(po);
}
void Boss::Detach(Observer* po) {
mol.remove(po);
}
void Boss::Notify() {
std::list<Observer*>::iterator it = mol.begin();
while (it != mol.end()) {
(*it)->updata(strat);
++it;
}
}
int main() {
Boss* pb = new Boss();
Observer* p1 = new Employee(pb);
Observer* p2 = new Dirver(pb);
Observer* p3 = new Reception(pb);
pb->Attach(p1);
pb->Attach(p2);
pb->Attach(p3);
//system("pause");
cout << "默认老板不在" << endl;
pb->Notify();//默认false 老板不在
cout << "老板来了" << endl;
pb->set(true);//老板来了
pb->Notify();
cout << "老板走了" << endl;//老板走了
pb->Detach(p2);
pb->set(false);
pb->Notify();
delete p1;
delete p2;
delete p3;
return 0;
}
测试用例:
四、应用场景
观察者模式的应用场景:购票系统、
场景描述:
* 某网上购票系统以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:
* 1、购票后记录文本日志
* 2、购票后记录数据库日志
* 3、购票后发送短信
* 4、购票送抵扣卷、兑换卷、积分
* 5、其他各类活动等
传统解决方案:
* 在购票逻辑等类内部增加相关代码,完成各种逻辑。
存在问题:
* 1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
* 2、日积月累后,文件冗长,导致后续维护困难。
存在问题原因主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,同时也符合面向接口编程的思想。
观察者模式典型实现方式:
* 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
* 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
* 3、主题类注册自己需要通知的观察者
* 4、主题类某个业务逻辑发生时通知观察者对象,每个观察者执行自己的业务逻辑。