设计模式 (二)——观察者模式(Observer,行为型)
2017-02-25 21:19
579 查看
1.概述
使用设计模式可以提高代码的可复用性、可扩充性和可维护性。观察者模式(Observer Pattern)属于行为型模式,在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。例如,在实际生活中,报纸出版社和订阅者之间存在着一对多的关系。当你向出版社订阅报纸时,只要他们有新报纸出版,就会送一份过来。当你不需要看报纸,可以取消订阅。只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消报纸。实际上,出版社+订阅者=观察者模式。观察者模式中,出版社被称为”主题”(Subject),订阅者被称为”观察者”(Observer)。关系如下图所示:
主题与观察者定义了一对多的关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。
观察者模式结构图:
Subject:抽象主题(抽象被观察者),抽象主题对象把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题(具体被观察者),将有关状态存入具体观察者对象,在具体主题内部状态发生改变时,给所有注册的观察者发送通知。
Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
ConcrereObserver:具体观察者,是实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
2.实例
下面给出实际的应用场景,以C++为例,使用观察者模式来解决问题。假设现在需要完成公司的一个项目,气象站项目。气象站的数据由WeatherData对象提供,包括温度、湿度和气压。项目要求有两种布告板,分别显示目前状况(CurrentStatus)和气象统计(Statistics)。当WeatherData对象获得最新的测量数据时,两种布告板必须实时更新。而且,这是一个可以扩展的气象站,需要公布一组API,好让其他开发人员可以写出自己的布告板。
2.1丑陋的设计
//C++示例代码,运行于VS2015 #include <stdlib.h> #include <iostream> using namespace std; //目前状况类:CurrentStatus class CurrentStatus { float temperature=0; //C++11特性,可直接给类成员数据赋默认值 float humidity=0; float pressure=0; public: //显示当前气象信息 void display() { cout << "CurrentStatus :"<< endl; cout << "temperature:" << temperature << " humidity:" << humidity<<" pressure:" <<pressure << endl; } //更新状态 void update(float temperature,float humidity,float pressure) { this->temperature= temperature; this->humidity= humidity; this->pressure= pressure; display();//显示当前气象信息 }; }; //气象统计类:Statistics class Statistics { float minTemperature=3.4e+38;//最低温度 float maxTemperature=-3.4e+38; //最高温度 public: //显示气象统计 void display() { cout << "Statistics :" << endl; cout << "minTemperature:" << minTemperature << " " << "maxTemperature:" << maxTemperature << endl; } //更新状态 void update(float temperature,float humidity,float pressure) { this->minTemperature = temperature<this->minTemperature? temperature: this->minTemperature; this->maxTemperature= temperature>this->maxTemperature ? temperature : this->maxTemperature; display();//显示气象统计 }; }; //WeatherData类 class WeatherData { public: float getTemperature(){ return 1; };//仅作示意,简单实现 float getHumidity(){ return 2; }; float getPressure(){ return 3; }; void measurementChanged(); }; void WeatherData::measurementChanged(){ float temp = getTemperature(); float humidity = getHumidity(); float pressure = getPressure(); CurrentStatus cs; cs.update(temp, humidity, pressure); Statistics sta; sta.update(temp,humidity, pressure); } int main() { WeatherData wd; wd.measurementChanged(); system("pause"); }
程序执行结果:
CurrentStatus : temperature:1 humidity:2 pressure:3 Statistics : minTemperature:1 maxTemperature:1
上面的实现我们能够初步完成气象站所需的功能 ,但是存在以下缺点:在实现函数measurementChanged时,当气象站数据更新时,可以及时的使每一个布告板进行实时更新。但是针对具体实现编程,会导致以后再增加或删除布告板时必须修改measurementChanged。
2.2使用观察者模式
具体实现如下。抽象观察者(Observer)。里面定义了一个更新的方法:
class Observer { public: virtual void update(float temperature,float humidity,float pressure)=0; };
具体观察者(Concrete Observer)。布告板是观察者,里面实现了更新的方法:
//目前状况布告板:CurrentStatus class CurrentStatus:public Observer{ ... public: //具体实现更新接口函数 void update(float temperature,float humidity,float pressure){ //同上 } //显示当前气象信息 void display(){...} //同上 }; //气象信息统计布告板:Statistics class Statistics:public Observer{ ... public: //具体实现更新接口函数 void update(float temperature,float humidity,float pressure{ //同上 } //显示气象统计信息 void display(){...} //同上
抽象被观察者(Subject)。抽象主题提供了注册attach、移除detach和通知notify三个纯虚函数,供具体被观察者实现:
class Subject{ public: virtual void attach(Observer*)=0; virtual void detach(Observer*)=0; virtual void notify()=0; };
具体被观察者(Concrete Subject)。这里的WeatherData类是具体主题(具体被观察者),具体实现如下:
class WeatherData:public Subject{ float temperature=0; float humidity=0; float pressure=0; list<Observer*> list; //用于记录注册的观察者 public: //实现注册 void attach(Observer* o){ list.push_back(o); } //实现移除 void detach(Observer* o){ for(auto it=list.begin();it!=list.end();++it){ if(*it==o){ list.erase(it); break; } } } //实现通知所有的观察者 void notify(){ for(auto it=list.begin();it!=list.end();++it){ (*it)->update(temperature,humidity,pressure); } } //设置观测值 void setMeasurements(float temperature,float humidity,float pressure){ this->temperature= temperature; this->humidity= humidity; this->pressure= pressure; this->notify();//观测值更新,通知观察者 } //WeatherData的其他方法 };
气象站已经通过观察者模式完成了建立,下面开始测试。
int main() { WeatherData wd; //注册布告板(观察者) wd.attach(new CurrentStatus); wd.attach(new Statistics); //检测到新的气象值,通知布告板进行更新 wd.setMeasurements(1.0,2.0,3.0); wd.setMeasurements(1.1, 2.1, 3.1); system("pause"); }
程序运行结果:
CurrentStatus : temperature:1 humidity:2 pressure:3 Statistics : minTemperature:1 maxTemperature:1
CurrentStatus :
temperature:1.1 humidity:2.1 pressure:3.1
Statistics :
minTemperature:1 maxTemperature:1.1
我们成功了使用了观察者模式,完成了气象站项目的设计和实现。观察者模式提供了一种对象设计,让主题和观察者之间松耦合,它们之间依然可以交互,但是不太清楚彼此的细节。
任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。事实上,在运行时我们可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也可以在任何时候删除某些观察者,或者注册某些观察者。此外,当有新类型的观察者出现时,主题的代码不需要修改,只要将新类型的观察者实现Observer接口,然后注册即可。
事实上,我们还可以独立的复用主题或观察者,并且改变主题或观察者中的一方,不会影响另一方,因为二者是松耦合。松耦合的设计可以让我们建立有弹性的OO系统,能够应对变化,因为对象之间的相互依赖降到了最低。所以,我们要坚持一个OO设计原则:为了交互对象之间的松耦合设计而努力。
3.观察者模式的应用场景和优缺点
使用场景:(1)关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
(2)事件多级触发场景。跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点:
解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
缺点:
在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且消息的通知一般是顺序执行,如果一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
4.小结
(1)OO设计原则:为了交互对象之间的松耦合设计而努力。(2)观察者模式:在对象之间定义一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
参考文献
[1]Freeman E.,Freeman E.,Sierra K.,et al.设计模式[M].第一版O’Reilly Taiwan公司译.北京:中国电力出版社,2015:38-75[2] 设计模式(五)观察者模式
相关文章推荐
- C++设计模式 -> 行为型 -> 观察者模式(Observer Pattern)
- 设计模式-行为型-观察者模式(Observer)
- 设计模式笔记--行为型模式之七Observer--观察者
- 设计模式13---设计模式之观察者模式(Observer)(行为型)
- 设计模式(19)-行为型-观察者模式(Observer)
- 二十二.行为型设计模式——Observer Pattern(观察者模式)
- Observer观察者设计模式(对象行为型)
- 设计模式学习之观察者模式(Observer,行为型模式)(7)
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
- 设计模式 ( 十七 ):Observer 观察者模式 -- 行为型
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
- "围观"设计模式(19)--行为型之观察者模式(Observer Pattern)
- 设计模式(4)-行为型-观察者模式(Observer)
- 设计模式笔记 18. Observer 观察者模式(行为型模式)
- 设计模式----行为型模式之观察者模式(Observer Pattern)
- 设计模式-- 观察者模式Observer(对象行为型)
- 设计模式—行为型-Observer(观察者)
- 设计模式(4)-行为型-观察者模式(Observer)
- 设计模式----行为型模式之观察者模式(Observer Pattern)