观察者模式(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函数!