设计模式学习笔记②-观察者模式

观察者模式

定义:观察者模式定义了对象之间的一对多依赖,这样一来当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

    假如我们有一个报社,和一些客户。我是其中的一个客户,报社每当一有报纸要出版就会给所有订阅过报纸的客户进行送报。客户如果取消订报服务的话,报社就会将客户从订阅名单中删除,之后这个客户就不会再收到报纸了。

松耦合的威力

  当两个对象之间松耦合,它们依然可以交互,但是不清楚彼此的细节。观察者模式提供了一种对象设计,让主题与观察者之间松耦合。

  为什么呢?

  关于观察者的一切,主题只知道观察者实现了某个接口(也就是oberver接口)。主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。

任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,在运行时我们可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样的也可以在任何时候删除某些观察者。

有新类型的观察者出现时,主题的代码也不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新类型里实现观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。

我们可以独立地复用主题或观察者。如果我们要在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。

改变主题或观察者其中一方,并不会影响另一方。因为两者是松耦合的,所以只要他们之间的接口仍被遵守,我们就可以自由地改变他们。

这里又收到一个设计原则:为了交互对象之间的松耦合设计而努力。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。

#include <vector>
#include <algorithm>
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 notifyObeserver() = 0;
	void MeasureMentChanged();
};
class WeatherData :public Subject {
private:
	vector<Observer*> *observers;
	float tempature;
	float humidity;
	float pressure;
public:
	WeatherData()
	{
		observers = new vector<Observer*>();
	}
	void registerObserver(Observer* o)
	{
		observers->push_back(o);
	}
	void removeObserver(Observer* o)
	{
		//等会看看effective stl
		auto res=find(observers->begin(), observers->end(), o);
		if (res!=observers->end())
			observers->erase(res);
	}
	void notifyObeserver()
	{
		for (vector<Observer*>::size_type i = 0; i < observers->size(); i++)
		{
			(*observers)[i]->update(tempature, humidity, pressure);
		}
	}
	void MeasureMentChanged()
	{
		notifyObeserver();
	}
	void set_Changed(float tempature, float humidity, float pressure)
	{//此方法只是用来测试用,实际项目中这些数据是从其他接口获得
		this->tempature = tempature;
		this->humidity = humidity;
		this->pressure = pressure;
		MeasureMentChanged();
	}
};
class DisplayElement
{
public:
	virtual void Diaplay() = 0;
};
class CurrentConditionDisplay :public Observer, public DisplayElement
{
private:
	Subject* weatherData;//定义一个这样的成员变量的目的是 方便自由取消注册
	float temerature;
	float humidity;
	float weatherData;
	CurrentConditionDisplay(Subject* weatherData)
	{
		this->weatherData = weatherData;
		weatherData->registerObserver(this);
	}
	void update(float temperature, float humidity, float pressure)
	{
		this->temerature = temperature;
		this->humidity = humidity;
		Diaplay();
	}
	void Diaplay()
	{
	   //打印气象信息
	}
};

总结:

     1.每一个观察者都有一个对主题的引用。这是为了便于以后如果我们要取消注册的话,可以直接通过这个引用操作。

     2.观察者有两种形式:

      ①推  

      当数据到位就立刻推给所有的观察者。

     ②拉

     当数据到位时,只通知观察者,观察者根据需求自己去拉数据。所以主题要提供一个访问所有数据的接口。

     3.我们还可以将主题设计一个状态位,用一个setChanged方法修改这个状态位,好让让notifyObeserver知道当他被调用时应该通知观察者。如果调用notifyObserver之前没有先调用setChanged(),观察者就不会被通知。这样做有其必要性,setchanged方法可以让你在更新观察者时,有更多的弹性,你可以更适当地通知观察者。比方说,如果没有setChanged(),我们的气象站测量是如此敏锐,以以致于温度计读数每十分之一就会更新。这会造成了WeatherData对象持续不断地通知观察者,我们并不希望看到这样的事情发生。如果我们希望半度以上才更新,就可以在温度差距到达半度时,调用setChanged(),进行有效的更新。

    

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值