Head First 设计模式——观察者模式(Observer Pattern)

本文深入探讨了观察者模式,这是一种定义对象间一对多依赖关系的模式,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在Internet气象站的例子中,WeatherData对象的更新会触发多个布告板实时更新。通过实现Observer接口,对象可以轻松地加入或退出观察者列表,实现松耦合。观察者模式既可以采用‘推’的方式将所有数据传递给观察者,也可以让观察者按需‘拉取’所需数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

观察者模式(Observer Pattern)

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并且自动更新。并且有“推”和“拉”两种通知方式。


设计原则:为了交互对象之间的松耦合设计而努力


问题:

现在需要建立一个Internet 气象站,WeatherData 对象可以追踪目前的天气状况,现在有三个布告板,分别显示目前的状况,气象统计以及简单的预报。当WeatherData获取了最新的数据的时候,三种布告板必须实时更新。


下面来看一个例子:

鸭子对象过来告诉主题,它想当一个观察者


鸭子对象现在已经成为正式观察者


主题有了新数据,现在鸭子可以收到数据


老鼠对象要求从观察者中把自己除名


老鼠离开了


主题有了新数据,老鼠接收不到


定义观察者模式的类图:

#include<iostream>
#include<list>
using namespace std;

class Observer{
public:
	virtual void update(float temp,float humidity, float pressure) = 0;
};
class Subject{
public:
	virtual void registerObserver(Observer *o) = 0;
	virtual void removeObserver(Observer *o) = 0;
	virtual void notifyObservers() = 0;
};
class DisplayElement{
public:
	virtual void display() = 0;
};

class WeatherData: public Subject{
public:
	WeatherData(){
		observers.clear();
	}
	void registerObserver(Observer *o){
		observers.push_back(o);
	}
	void removeObserver(Observer *o){
		observers.remove(o);
	}
	void notifyObservers(){
		for( list<Observer *>::iterator it = observers.begin(); it != observers.end(); ++it){
			(*it)->update(temperature,humidity,pressure);
		}
	}
	void measurementsChanged(){
		notifyObservers();
	}
	void setMeasurements(float temperature, float humidity,float pressure){
		this->temperature = temperature;
		this->humidity = humidity;
		this->pressure = pressure;
		//可以根据获取的数据来判断要不要设置
		measurementsChanged();
	}
private:
	list<Observer*> observers;
	float temperature;
	float humidity;
	float pressure;
};
class CurrentConditionsDisplay: public Observer,public DisplayElement{
public:
	CurrentConditionsDisplay(Subject * weatherData){
		this->weatherData = weatherData;
		//注册成为观察者
		this->weatherData->registerObserver(this);
	}
	~CurrentConditionsDisplay(){
	}
	void update(float temperature,float humidity,float pressure){
		this->temperature = temperature;
		this->humidity = humidity;
		//继承的方法被重写
		display();
	}
	void display(){
		cout << "Current conditions:"   << temperature 
			<< "F degrees and" << humidity 
			<< "%humidity" << endl;
	}
private:
	float temperature;
	float humidity;
	Subject * weatherData;
};
int main(){
	WeatherData  *weatherData = new WeatherData();
	CurrentConditionsDisplay *currentDisplay = new CurrentConditionsDisplay(weatherData);
	//可以自己定义其他的display 类型
	//StatisticDisplay *statisticsDisplay = new StatisticDisplay(weatherData);
	weatherData->setMeasurements(80,65,30.4f);
	weatherData->setMeasurements(82,70,29.2f);
	delete weatherData;
	delete currentDisplay;
}

     上述的设计充分体现了松耦合的原则。当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。关于观察者的一切,主题只知道观察者实现了某个接口(Observer 纯虚类),并不需要知道观察者的具体类是谁、做了些什么或其他细节。任何时候我们可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。

     假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所要做的就是在新的类里实现此观察者的接口,然后注册观察者即可。


        上述的设计其实还存在一些问题,当数据改变的时候,主题“推”所有数据给观察者,即使这些数据不是必须的(上例中的pressure数据)。观察者模式还有另外一种思路,观察者提供getter 方法,当需要时,观察者来“拉”走自己所需要的数据。HeadFirst 上面是利用Java提供的接口实现的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值