设计模式之观察者模式C++实现
Posted 今天也要努力搬砖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之观察者模式C++实现相关的知识,希望对你有一定的参考价值。
参考书籍《Head First设计模式》
设计模式和设计原则
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
观察者模式遵循的设计原则:
为了交互对象之间的松耦合设计而努力。
观察者模式中的类
提到观察者模式,常常会看到类似于下面的图,图片链接设计模式-观察者模式 C++实现_不很正派的专栏-CSDN博客_c++观察者模式,侵删。下图中包含了观察者中用到的类,其中Subject主题类(主题类有些地方也叫可观察者/被观察者Observable),被观察的类都继承自这个类,该类中声明了实现registerObserver用来添加观察者、removeObserver用来移除观察者、notifyObservers通知观察者的方法。ConcreteSubject具体主题类,继承自主题类。Observer抽象观察者类,声明了update方法,被观察者通知观察者就是通过调用该方法。ConcreteObserver具体观察者继承自抽象观察者类,实现update方法。
该模式中观察者获取数据有两种方式。一种是“推”的方式,即观察者被动接受数据。主题通知观察者有变更时,就把数据推给观察者。另一种是“拉”的方式,即观察者主动获取数据。主题通知时把自己的引用传给观察者,观察者按照自己需要,使用主题提供的接口获取数据。下面案例中使用的是"拉"的方式。
案列描述
气象监测系统的实现。气象站监测气象数据,布告板显示气象数据。有两块布告板,分别显示目前状况(温度、湿度、气压)和天气预报。使用观察者模式,气象站为具体主题,气象板是观察者,当气象数据改变时通知气象板。
代码实现
声明:类的声明和实现在同一个文件里是个坏习惯,坏习惯,坏习惯,但因为我懒,还是写一起了,大家不要效仿,要引以为戒,要引以为戒,要引以为戒。
定义主题类Subject,该类中实现了registerObserver、removeObserve、notifyObservers三个函数,代码如下
//主题类
class Subject{
public:
//注册观察者
void registerObserver(Observer* o)
{
m_observers.push_back(o);
}
//移除观察者
void removeObserver(Observer* o)
{
for (std::vector<Observer*>::iterator iter = m_observers.begin();
iter != m_observers.end(); iter++)
{
if (*iter == o)
{
m_observers.erase(iter);
return;
}
}
}
//通知观察者
void notifyObservers()
{
for (std::vector<Observer*>::iterator iter = m_observers.begin();
iter != m_observers.end(); iter++)
{
(*iter)->update(this);
}
}
private:
std::vector<Observer*> m_observers;
};
定义WeatherData继承自Subject,是观察者模式中的具体主题,其代码如下。其中getter接口是供观察者获取数据使用(采用"拉"的方式主动获取数据)。setter接口是用来设置数据。
//具体主题类
class WeatherData :public Subject{
public:
声明获得状态的接口,采用“拉”的方式获取状态时使用
float getTemperature(){ return m_temperature; }
float getHumidity(){ return m_humidity; }
float getPressure(){ return m_pressure; }
std::string getPreWeather(){ return m_preWeather; }
//设置天气状态,通知观察者
void setMeasurements(float temperature, float humidity, float pressure, std::string preWeather)
{
m_temperature = temperature;
m_humidity = humidity;
m_pressure = pressure;
m_preWeather = preWeather;
notifyObservers();
}
private:
float m_temperature;
float m_humidity;
float m_pressure;
std::string m_preWeather;
};
观察者类以及具体观察者类的定义如下。主要就是在update方法中获取数据,并调用显示接口
//观察者类
class Observer{
public:
//通过“推”的方式获取数据,参数为各种状态数据
//virtual void update(float temperature,float humidity,float pressure) = 0;
//通过“拉”的方式获取数据,参数为subject指针
virtual void update(Subject* subject) = 0;
};
class Dislay
{
public:
virtual void dislay() = 0;
};
//具体观察者,当前温度湿度压强
class CurrentonditionsDisplay :public Observer, public Dislay{
public:
virtual void update(Subject* subject)
{
WeatherData* weatherData = (WeatherData*)subject;
m_temperature = weatherData->getTemperature();
m_humidity = weatherData->getHumidity();
m_pressure = weatherData->getPressure();
dislay();
}
void dislay()
{
std::cout << "current temperature:" << m_temperature << std::endl;
std::cout << "current humidity:" << m_humidity << std::endl;
std::cout << "current pressure:" << m_pressure << std::endl;
}
private:
float m_temperature;
float m_humidity;
float m_pressure;
};
//具体观察者,天气预报气象板
class WeatherPredictionDisplay :public Observer{
public:
virtual void update(Subject* subject)
{
WeatherData* weatherData = (WeatherData*)subject;
m_preWeather = weatherData->getPreWeather();
dislay();
}
void dislay()
{
std::cout << "Weather Prediction:" << m_preWeather << std::endl;
}
private:
std::string m_preWeather;
};
最后在main函数中,写测试代码如下
int main()
{
WeatherData* weatherData=new WeatherData();
CurrentonditionsDisplay* currentonditionsDisplay = new CurrentonditionsDisplay();
WeatherPredictionDisplay* weatherPredictionDisplay = new WeatherPredictionDisplay();
//注册为观察者(书上是在构造函数中注册的)
weatherData->registerObserver(currentonditionsDisplay);
weatherData->registerObserver(weatherPredictionDisplay);
//改变天气状态数据
weatherData->setMeasurements(80, 65, 30, "Sunny");
weatherData->setMeasurements(82, 79, 29, "Rain");
weatherData->setMeasurements(78, 90, 28, "Snow");
delete weatherData;
delete currentonditionsDisplay;
delete weatherPredictionDisplay;
system("pause");
}
执行结果
以上是关于设计模式之观察者模式C++实现的主要内容,如果未能解决你的问题,请参考以下文章