版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rl529014/article/details/82228891
概念解释
比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,具体目标调度观察者的更新方法。
比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文。
代码示例:(代码基于Qt、C++)
#include <QCoreApplication>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;
//订阅者基类
class ObserverBoardInterface
{
public:
virtual void update(float a,float b,float c) = 0;
};
//订阅者基类
class DisplayBoardInterface
{
public:
virtual void show() = 0;
};
// The Abstract Subject
//发布者基类
class WeatherDataInterface
{
public:
virtual void registerOb(ObserverBoardInterface* ob) = 0;
virtual void removeOb(ObserverBoardInterface* ob) = 0;
virtual void notifyOb() = 0;
};
// The Concrete Subject
//消息发布者
class ParaWeatherData: public WeatherDataInterface
{
public:
void SensorDataChange(float a,float b,float c)
{
m_humidity = a;
m_temperature = b;
m_pressure = c;
notifyOb(); //通知消息订阅者
}
void registerOb(ObserverBoardInterface* ob)
{
m_obs.push_back(ob);
}
void removeOb(ObserverBoardInterface* ob)
{
m_obs.remove(ob);
}
protected:
void notifyOb()
{
list<ObserverBoardInterface*>::iterator pos = m_obs.begin();
while (pos != m_obs.end())
{
((ObserverBoardInterface* )(*pos))->update(m_humidity,m_temperature,m_pressure);
(dynamic_cast<DisplayBoardInterface*>(*pos))->show();
++pos;
}
}
private:
float m_humidity;
float m_temperature;
float m_pressure;
list<ObserverBoardInterface* > m_obs; //存储消息订阅者
};
// A Concrete Observer
//消息订阅者
class CurrentConditionBoard : public ObserverBoardInterface, public DisplayBoardInterface
{
public:
CurrentConditionBoard(ParaWeatherData& a):m_data(a)
{
m_data.registerOb(this);
}
void show()
{
cout<<"_____CurrentConditionBoard_____"<<endl;
cout<<"humidity: "<<m_h<<endl;
cout<<"temperature: "<<m_t<<endl;
cout<<"pressure: "<<m_p<<endl;
cout<<"_______________________________"<<endl;
}
void update(float h, float t, float p)
{
m_h = h;
m_t = t;
m_p = p;
}
private:
float m_h;
float m_t;
float m_p;
ParaWeatherData& m_data;
};
// A Concrete Observer
//消息订阅者
class StatisticBoard : public ObserverBoardInterface, public DisplayBoardInterface
{
public:
StatisticBoard(ParaWeatherData& a):m_maxt(-1000),m_mint(1000),m_avet(0),m_count(0),m_data(a)
{
m_data.registerOb(this);
}
void show()
{
cout<<"________StatisticBoard_________"<<endl;
cout<<"lowest temperature: "<<m_mint<<endl;
cout<<"highest temperature: "<<m_maxt<<endl;
cout<<"average temperature: "<<m_avet<<endl;
cout<<"_______________________________"<<endl;
}
void update(float h, float t, float p)
{
++m_count;
if (t>m_maxt)
{
m_maxt = t;
}
if (t<m_mint)
{
m_mint = t;
}
m_avet = (m_avet * (m_count-1) + t)/m_count;
}
private:
float m_maxt;
float m_mint;
float m_avet;
int m_count;
ParaWeatherData& m_data;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ParaWeatherData * wdata = new ParaWeatherData; //发布者
CurrentConditionBoard* currentB = new CurrentConditionBoard(*wdata); //注册订阅者
StatisticBoard* statisticB = new StatisticBoard(*wdata); //注册订阅者
wdata->SensorDataChange(10.2, 28.2, 1001); //发布消息
wdata->SensorDataChange(12, 30.12, 1003);
wdata->SensorDataChange(10.2, 26, 806);
wdata->SensorDataChange(10.3, 35.9, 900);
wdata->removeOb(currentB); //移除订阅者
wdata->SensorDataChange(100, 40, 1900);
delete statisticB;
delete currentB;
delete wdata;
return a.exec();
}
其实观察者模式还是挺容易理解的,如果你还没有理解的话,
我再举一个栗子,通过下面的描述,在配合上面的程序demo,会更加容易理解观察者模式。
- 需求:
有用户A、B、C三个人,我们称呼他们为订阅者;报社机构D,负责记录订阅者的信息,并配送报纸。 - 订阅者注册:
A、B、C三个人如果想要每天能够阅读最新的报纸,就需要到D那里去提出申请,并留存报箱地址,D将报纸订阅者的报箱位置记录下来。 - 发布者发布消息:
每天早上,D会根据自己的记录本,按顺序投递报纸到对应的订阅者的报箱。
(此处不区分观察者模式和发布者订阅者模式的区别)