1. 观察模式
- 考察报纸发行过程,一些家庭向报纸销售商进行了订阅,销售商定期把报纸放到家庭门口
家庭购报纸的过程叫做注册过程
销售商发行报纸的过程是推送过程
销售商和家庭之间是一对多的关系
2. 总体设计
注意事项:Observer 和 Subject 放在同一个进程中!!!

2.1 接口说明
registerObserver(Observer& O);
输入参数:观察者对象的引用。
函数功能:Subject负责把Observer 添加到订阅者列表中
removeObserver(Observer& O);
输入参数:观察者对象的引用
函数功能:Subject负责把Observer从订阅者列表中删除
notifyObservers(void);
函数功能:Subject负责更新所有订阅者的数据
update();
函数功能:Observer根据输入数据完成数据更新
2.2 设计方案1:Observer 和 Subject

2.2.1 方案说明
该设计存在多项缺陷。
- Subject 和 Observer接口设计原则上应该彼此独立。但是update接口进行了Hard Code。
void update (float temp, float humi, float pressure);更好的方法将在2.2小节中说明

2.2.2 实现代码
#include <iostream>
#include <list>
using namespace std;
class DisplayElement
{
public:
virtual void display (void) = 0;
};
class Observer
{
public:
virtual void update (float temp, float humi, float pressure) = 0;
};
class ForcastDisplay:public DisplayElement, public Observer
{
public:
ForcastDisplay (void)
{
m_temperature = 0;
m_pressure = 0;
m_humidity = 0;
m_future = 0;
}
void update (float temp, float humi, float pressure)
{
m_temperature = temp;
m_pressure = pressure;
m_humidity = humi;
m_future = temp * humi - pressure;
display ();
}
private:
void display (void)
{
cout << "ForcastDisplay::" << __FUNCTION__ << " Current temp=" <<
m_temperature << " pressure=" << m_pressure << " humidity=" <<
m_humidity << " // future=" << m_future << endl;
}
float m_temperature;
float m_pressure;
float m_humidity;
float m_future;
};
class Subject
{
public:
virtual void registerObserver (Observer * O) = 0;
virtual void removeObserver (Observer * O) = 0;
virtual void notifyObservers (void) = 0;
};
class WeatherData:public Subject
{
public:
WeatherData (void)
{
m_temperature = 0;
m_humidity = 0;
m_pressure = 0;
}
void setMeasurements (void)
{
m_temperature = getTemperature ();
m_humidity = getHumidity ();
m_pressure = getPressure ();
measurementsChanged ();
}
void removeObserver (Observer * O)
{
observers.remove (O);
}
void registerObserver (Observer * O)
{
observers.push_back (O);
}
private:
void notifyObservers (void)
{
for (std::list < Observer * >::iterator it = observers.begin ();
it != observers.end (); ++it)
{
auto observerObj = *it;
observerObj->update(m_temperature,m_humidity,m_pressure);
}
}
void measurementsChanged (void)
{
notifyObservers ();
}
float getTemperature (void)
{
cout << "fake WeatherData temperature =30" << endl;
return 30;
}
float getHumidity (void)
{
cout << "fake WeatherData humidity = 0.3" << endl;
return 0.3;
}
float getPressure (void)
{
cout << "fake WeatherData pressure = 10" << endl;
return 10;
}
float m_temperature;
float m_humidity;
float m_pressure;
std::list < Observer * >observers;
};
int
main ()
{
ForcastDisplay *ptrForcastObj = new ForcastDisplay;
WeatherData *ptrWeatherDataObj = new WeatherData;
ptrWeatherDataObj->registerObserver (ptrForcastObj);
ptrWeatherDataObj->setMeasurements ();
ptrWeatherDataObj->removeObserver (ptrForcastObj);
delete ptrForcastObj;
delete ptrWeatherDataObj;
return 0;
}
输出:
fake WeatherData temperature =30
fake WeatherData humidity = 0.3
fake WeatherData pressure = 10
ForcastDisplay::display Current temp=30 pressure=10 humidity=0.3 // future=-1
2.3 设计方案1:数据模型改进方案
2.3.1 设计思路
void update (float temp, float humi, float pressure);
无法将Subject和Observer很好的进行解耦,因此我们使用数据模型进行取代

2.3.2 实现代码
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
class Subject;
class Observer;
class DataModel
{
public:
std::map<string,float> dataKeyValpair;
};
class DisplayElement
{
public:
virtual void display (void) = 0;
};
class Observer
{
public:
virtual void update (Subject& S, DataModel& dataObj) = 0;
};
class ForcastDisplay:public DisplayElement, public Observer
{
public:
ForcastDisplay (void)
{
m_temperature = 0;
m_pressure = 0;
m_humidity = 0;
m_future = 0;
}
void update (Subject& S, DataModel& dataObj)
{
m_temperature = dataObj.dataKeyValpair["temp"];
m_pressure = dataObj.dataKeyValpair["pres"];
m_humidity = dataObj.dataKeyValpair["humi"];
m_future = m_temperature * m_humidity - m_pressure;
display ();
}
private:
void display (void)
{
cout << "ForcastDisplay::" << __FUNCTION__ << " Current temp=" <<
m_temperature << " pressure=" << m_pressure << " humidity=" <<
m_humidity << " // future=" << m_future << endl;
}
float m_temperature;
float m_pressure;
float m_humidity;
float m_future;
};
class Subject
{
public:
virtual void registerObserver (Observer * O) = 0;
virtual void removeObserver (Observer * O) = 0;
virtual void notifyObservers (void) = 0;
};
class WeatherData:public Subject
{
public:
WeatherData (void)
{
m_temperature = 0;
m_humidity = 0;
m_pressure = 0;
}
void setMeasurements (void)
{
m_temperature = getTemperature ();
m_humidity = getHumidity ();
m_pressure = getPressure ();
measurementsChanged ();
}
void removeObserver (Observer * O)
{
observers.remove (O);
}
void registerObserver (Observer * O)
{
observers.push_back (O);
}
private:
void notifyObservers (void)
{
DataModel data;
data.dataKeyValpair["temp"] = m_temperature;
data.dataKeyValpair["pres"] = m_pressure;
data.dataKeyValpair["humi"] = m_humidity;
for (std::list < Observer * >::iterator it = observers.begin ();
it != observers.end (); ++it)
{
auto observerObj = *it;
observerObj->update(*this, data);
}
}
void measurementsChanged (void)
{
notifyObservers ();
}
float getTemperature (void)
{
cout << "fake WeatherData temperature =30" << endl;
return 30;
}
float getHumidity (void)
{
cout << "fake WeatherData humidity = 0.3" << endl;
return 0.3;
}
float getPressure (void)
{
cout << "fake WeatherData pressure = 10" << endl;
return 10;
}
float m_temperature;
float m_humidity;
float m_pressure;
std::list < Observer * >observers;
};
int
main ()
{
ForcastDisplay *ptrForcastObj = new ForcastDisplay;
WeatherData *ptrWeatherDataObj = new WeatherData;
ptrWeatherDataObj->registerObserver (ptrForcastObj);
ptrWeatherDataObj->setMeasurements ();
ptrWeatherDataObj->removeObserver (ptrForcastObj);
delete ptrForcastObj;
delete ptrWeatherDataObj;
return 0;
}
2.4 应用场景
Observer和Subject 的实际应用可以考虑如下几种
- 可以不在同一台主机上,
- 在同一台主机的不同进程中
- 同一进程的不同线程中
一个好的框架应该可以兼容以上三种情形,待扩展
本文探讨了如何通过数据模型优化Observer-Subject设计,以解决Update接口硬编码的问题。通过将Subject和Observer解耦,实现更灵活的数据传递。实例展示了如何在不同场景下应用,如跨进程、跨线程和分布式系统中.

被折叠的 条评论
为什么被折叠?



