文章目录

  • 1.概述
  • 2.实例
    • 2.1 丑陋的设计
    • 2.2 使用观察者模式
  • 3.应用场景
  • 4.优缺点
  • 5.小结
  • 参考文献

1.概述

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。观察者模式(Observer Pattern)属于行为型模式,在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

例如,在实际生活中,报纸出版社和订阅者之间存在着一对多的关系。当你向出版社订阅报纸时,只要他们有新报纸出版,就会送一份过来。当你不需要看报纸,可以取消订阅。只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消报纸。实际上,出版社+订阅者=观察者模式。观察者模式中,出版社被称为"主题"(Subject),订阅者被称为"观察者"(Observer)。关系如下图所示:

主题与观察者定义了一对多的关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。

观察者模式结构图:

Subject:抽象主题(抽象被观察者),抽象主题对象把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题(具体被观察者),将有关状态存入具体观察者对象,在具体主题内部状态发生改变时,给所有注册的观察者发送通知。
Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
ConcrereObserver:具体观察者,是实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

2.实例

下面给出实际的应用场景,以C++为例,使用观察者模式来解决问题。

假设现在需要完成公司的一个项目,气象站项目。气象站的数据由WeatherData对象提供,包括温度、湿度和气压。项目要求有两种布告板,分别显示目前状况(CurrentStatus)和气象统计(Statistics)。当WeatherData对象获得最新的测量数据时,两种布告板必须实时更新。而且,这是一个可以扩展的气象站,需要公布一组API,好让其他开发人员可以写出自己的布告板。

2.1 丑陋的设计

以下代码运行于 VS 2015。

#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.优缺点

优点:

解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。

缺点:

在应用观察者模式时需要考虑一下开发效率和运行效率的问题。程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且消息的通知一般是顺序执行,如果一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

5.小结

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

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


参考文献

[1] Freeman E.,Sierra K.,et al.设计模式[M].第一版O’Reilly Taiwan公司译.北京:中国电力出版社,2015.P38-75
[2] 设计模式(五)观察者模式

行为型设计模式(4)—— 观察者模式(Observer Pattern)相关推荐

  1. 设计模式学习--观察者模式(Observer Pattern)

    设计模式学习--观察者模式(Oberser Pattern) 2013年5月18日 天气:热!  下午15:28  设计模式学习中 学习者:小巫 什么是观察者模式? 定义了对象之间的一对多依赖,这样一 ...

  2. 设计模式 -行为型模式_ 观察者模式Observer Pattern 之 JDK内置的实现

    文章目录 概念 Code [主题] [观察者s] 观察者一 观察者二 [测试] 源码分析 java.util.Observable 目标类 java.util.Observer 观察者接口 notif ...

  3. 锈才学设计模式之 —— 观察者模式(Observer Pattern)

    锈才学设计模式之  -- 观察者模式 观察者模式:定义对象的一对多的关系,这样当主题对象改变状态时,其它的观察者对象都会收到通知,自动更新. 说明: 在真实世界中存在很多类似的模型,比如:订报纸,找中 ...

  4. 设计模式----行为型模式之观察者模式(Observer Pattern)

    下面是阅读<Head First设计模式>的笔记. 观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新. JDK API内置机制 ...

  5. 设计模式-观察者模式(Observer Pattern)

    设计模式-观察者模式 观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应.在观察者模式中,发生改变的对象称为观 ...

  6. 设计模式 - 观察者模式(Observer Pattern) Java内置 用法

    观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...

  7. 设计模式:观察者模式--Observer

    一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...

  8. 设计模式(行为型)之观察者模式(Observer Pattern)

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  9. 行为型设计模式之观察者模式(Observer)

    在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变.例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心:还有,当我们开车到交叉路口 ...

  10. 极速理解设计模式系列:2.观察者模式(Observer Pattern)

    4个角色:被观察者(Subject/目标对象接口),具体被观察者(ConcreteSubject/具体目标对象),观察者(Observer),具体观察者(ConcreteObserver)       ...

最新文章

  1. Android 对象型数据库 db4o
  2. centos7 tmp目录 自动清理规则
  3. php 照片变成卡通照片,Photoshop实例:变照片为卡通漫画
  4. Linux: Nginx proxy_pass域名解析引发的故障
  5. struts+hibernate+oracle+easyui实现lazyout组件的简单案例——DeptDao层代码
  6. python平均分及格率优秀率_跪求:请问怎样统计均分、优秀率、及格率、低分率的问题...
  7. python turtle 海龟画图歌尔号 火箭 三体 地球
  8. Python——类和对象、魔术方法(day07)
  9. Oliver Wyman的一年制PTA面试
  10. MySQL 中 delete where in 语句的子查询限制
  11. 计算机网络实验:路由器交换机与其基本配置操作、常见命令
  12. [下属谈话]管理者与下属谈话的技巧以及注意点
  13. OTM order management(订单管理)--ORDER BASE
  14. mandatory和immediate
  15. layer.msg 延迟几秒跳转页面
  16. 【Google地球环游世界】Google Earth Pro for Mac 7.3.2
  17. 网络营销中的博客营销有什么价值?对于博客营销我们应该注意哪些问题?
  18. Labview上位机串口通信-读写
  19. FPGA学习笔记——wire和reg数据以及组合逻辑和时序逻辑
  20. 手把手教你用plotly绘制excel中常见的16种图表(下)

热门文章

  1. Mongodb 与 MySQL对比
  2. 作业MathExam
  3. 云计算网络基础第一天
  4. python字符串前面加u,r,b的含义
  5. AGC018C Coins (set)
  6. 六个角度深层区分ERP和MES的不同!
  7. Mysql存储引擎之TokuDB以及它的数据结构Fractal tree(分形树)
  8. 类对象工厂设计模式(Factory Pattern)
  9. [Python] L1-041 寻找250-PAT团体程序设计天梯赛GPLT
  10. PAT 乙级 1003. 我要通过!(20) Java版