《Head First设计模式》批注系列(一)——观察者设计模式

  最近在读《Head First设计模式》一书,此系列会引用源书内容,但文章内容会更加直接,以及加入一些自己的理解。

  观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

  引子

  我们的公司刚刚你拿下了一个中国气象局的一个招标,负责建立北京市的气象观测站。该气象站必须建立在中国气象局专利申请中的WeatherData对象上,有WeatherData对象负责追踪目前的天气状况,(由于本文只做例子,只追踪温度、湿度、气压)。气象站提出应用的要求:

  1、我们公司能建立一个应用,有三种布告板,可以显示实时天气状况、气象统计、以及简单的预报。

  2、当WeatherData对象获得最新的测量数据时,三种布告板必须实时更新。

  3、我们的气象站是可以扩展的,气象站希望可以公布一组API(接口),好让其他开发人员可以自己写出自己的气象公告板,并插入此应用

  初步设计

  1、首先根据气象站的需求,我们画一个示意图。

  

  WeatherData对象知道如何跟物理气象站联系,当数据跟新时,WeatherData对象从气象站获得数据,WeatherData对象随机更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计和天气预报,所以我们目前的主要任务是,利用WeatherData对象从气象站获取数据,并跟新三个布告板。

  在设计之前,我们要看一看气象站给我们WeatherData类(此处只做示意,代码后面会变得完整)

public class WeatherData {//下面的三个方法获取温度、湿度、以及压力public float getTemperature(){temperature=获取温度;return temperature;}public float getHumidity(){temperature=获取湿度;return humidity;}public float getPressure(){temperature=获取压力;return pressure;}//一旦气象测量更新、此方法就会被调用public void measurementsChanged(){}

  好了,到此为止我们已经知道了最终的设计要求以及气象站给我们的WeatherData类,下面我们就要开始设计我们的应用,根据我们知道的东西,我们可以先来一个不完整的初版,我们现在WeatherData中增加一些方法(不着急先写出方法的具体内容,只要写出一个方法名,记得它的功能即可)

public class WeatherData {    
//下面的三个方法获取温度、湿度、以及压力public float getTemperature(){temperature=获取温度;return temperature;}public float getHumidity(){temperature=获取湿度;return humidity;}public float getPressure(){temperature=获取压力;return pressure;}//一旦气象测量更新、此方法就会被调用public void measurementsChanged(){float temp = getTemperature();float humidity = getHumidity();float pressure = getPressure();

     currentConditionsDisplay.update(temp,humidity,pressure);
     statisticsDiaplay.updata(temp,humidity,pressure);
     forecastDisplay.update(temp,humidity,pressure);}

  这是我们第一次设计的程序,由于我们已经开始准备用设计模式了,所以我们可以看看我们目前的代码中是不是有还可以改进的地方,首先,我们看到了三个公告板都有update方法,那我们就可以把这个方法

抽取成一个接口,这样我们每次增加公告板时直接实现此接口就可以,其次,本次我们讨论的是观察者模式,那我们的引子就先说到这,我们开始看看什么是观察者设计模式,我们了解完观察者设计模式后,我们

再回到我们的引子,完成设计。

  认识观察者设计模式

  在生活中,订阅报纸就是就是一个观察者设计模式,报社的业务就是出版报纸,当你订阅了某家报社的报纸,只要报社有了新的报纸出版,他们就会给你送来,只要你是他们的订户,你就一定会收到报

纸,当你不想在看这家报纸时,你就可以取消订阅,他们就不会再送来新报纸。其实,出版社+订阅者就等于观察者模式,只是在这个模式里,出版社叫做“主题(Subject)”,订阅者叫做观察者"(Observer)”,如果

你还没有看懂,那我们来看下面这个图:

  

  图中主题对象管理者int数据,狗对象、猫对象、老鼠对象订阅了主题,一旦主题对象发生改变,就会给这些订阅了的对象发送数据,鸭子对象没有订阅主题,就不会接收到数据。

  有一天,鸭子对象突然对主题对象管理的数据起了兴趣,它就需要过去告诉主题,我对你的数据改变有兴趣,一有变化请告诉我,这就是“订阅”的过程,在这之后,鸭子对象就是正式

的观察者了,以后主题管理的数据再有改变就会告诉鸭子对象。

  又有一天,老鼠对象对主题说,你管理的数据我观察太久了,我不想再当你的观察者了,这时主题就删掉老鼠对象,每当数据再变化时,老鼠对象就不会接收到数据。

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

  下面是便是定义观察者设计模式的类图:

  

  观察者设计模式应用到我们的气象站中

  我们已经基本了解了观察者设计模式,那我们就可以回到我们的引子完成原来的设计

  初步思考

  通过我们在上面分析的观察者设计模式,我们发现这是模式是一对多的关系,每当一改变时,就会给多发送改变的数据,而在我们的气象站设计中,正是一对多的关系,一就是我们的WeatherData数据

多就是显示的布告板,而不同的布告板有相同和不同的方法,我们可以把相同的部分抽取成接口,实现代码的复用,那么下面就让我们参照上面观察者设计模式的类图画一下我们气象站的设计类图。(自己

先尝试一下哟)

  设计气象站

  

    实现气象站

    根据上面的类图,我们就可以完善我们的代码啦

    Subject类的接口及WeatherData实现

package com.frank.observe.subject;
import com.frank.observe.observer.Observer;public interface Subject {
  //主题注册、删除、通知观察者方法
public void registerObserver(Observer o);public void removeObserver(Observer o);public void notifyObserver();//信息改变时执行方法public void measurementsChanged(); }

 

package com.frank.observe.subject;
import java.util.ArrayList;
import com.frank.observe.observer.Observer;public class WeatherData implements Subject {
  //WeatherData实现了Subject方法
private ArrayList<Observer> observers;
  //包含温度、湿度、压力
private float temperature;private float humidity;private float pressure;//构造器创建观察者们的集合public WeatherData(){observers = new ArrayList<Observer>();}//接口方法@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {int i = observers.indexOf(o);if(i>=0){observers.remove(o);}}@Overridepublic void notifyObserver() {for(int i = 0;i<observers.size();i++){Observer observer = observers.get(i);observer.update(temperature, humidity, pressure);}}@Overridepublic void measurementsChanged() {notifyObserver();}//WeatherData自己的set方法,一会测试时在test中改变数据源public void setMeasurements(float temperature,float humidity, float pressure){this.temperature=temperature;this.humidity=humidity;this.pressure=pressure;measurementsChanged();}}

 

    Observer类的接口以及CurrentConditionDisplay实现

package com.frank.observe.observer;
//Observer接口中更新数据的方法
public interface Observer {public void update(float temp,float humidity,float pressure);
}
package com.frank.observe.observer;
import com.frank.observe.display.DisplayElement;
import com.frank.observe.subject.Subject;
import com.frank.observe.subject.WeatherData;
//显示板要实现Observer以及DisplayElement接口(及公共方法)
public class CurrentConditionDisplay implements Observer, DisplayElement {private float temprature;private float humidity;
  //将weatherData作为自己的成员变量
private Subject weatherData;//在带参构造器中将自己注册到weatherData中public CurrentConditionDisplay(Subject weatherData){this.weatherData=weatherData;weatherData.registerObserver(this);}//接口的更新方法@Overridepublic void update(float temp, float humidity, float pressure) {this.temprature=temp;this.humidity=humidity;
     //接口的显示方法display();}@Override
public void display() {System.out.println("current conditions" +temprature+"F degrees and"+humidity+"% humidity");}}

 

  DisplayElement接口

package com.frank.observe.display;public interface DisplayElement {public void display();
}

  Test方法

package com.frank.observe.test;
import com.frank.observe.observer.CurrentConditionDisplay;
import com.frank.observe.subject.WeatherData;public class Test {public static void main(String[] args) {
     //新建一个主题WeatherData weatherData
= new WeatherData();
     //新建一个公告板并将自己注册到主题中CurrentConditionDisplay currentDisplay
= new CurrentConditionDisplay(weatherData);
     //每当主题更新数据时发送给观察者,观察者显示在公告板中weatherData.setMeasurements(
80, 60, 30.4f);weatherData.setMeasurements(82, 70, 29.2f);weatherData.setMeasurements(78, 90, 29.2f);}}

 

   结果

current conditions80.0F degrees and60.0% humidity
current conditions82.0F degrees and70.0% humidity
current conditions78.0F degrees and90.0% humidity

 

   总结

   要点:

OO基础:抽象

OO原则:封装变化、多用组合,少用继承、针对接口编程,不针对实现编程

OO模式:观察者设计模式----在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会受到通知,并自动更新(后面的系列会看到其代表人物--MVC)

   

 

转载于:https://www.cnblogs.com/FrancisLiu/p/8728070.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PYPL 4 月排行:Python 最流行,Java 还行不行?

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; PYPL 发布了 4 月份的编程语言排行榜。 前五的分别是&#xff1a;Python、Java、Javascript、C# 和 PHP。可以看到&#xff0c;榜单没有什么大变化&#xff0c;但是相比去年 4 月份&#xff0c;…

两个向量的旋转矩阵与四元素

两向量的夹角 2017年06月20日 17:38:11 csxiaoshui 阅读数&#xff1a;36764 怎么计算两个向量间的夹角呢&#xff1f; 这里主要分两种情况&#xff0c;对于二维向量和三维向量来分别讨论。 1. 二维向量 二维向量的情况相对简单&#xff0c;根据向量间的点乘关系 v1⋅v2|…

顺序表

一、数据是如何在内存中存储的&#xff1f; 32位系统中char&#xff0c;int型数据在内存中的存储方式&#xff1a; char占1byte&#xff08;8bit&#xff09;int占4byte&#xff08;32bit&#xff09;假设我们有一个int类型的值&#xff0c;它从0x01开始&#xff0c;一个int占据…

Establishing SSL connection without server's identity verification is not recommended.

完全描述:Establishing SSL connection without servers identity verification is not recommended. According to MySQL 5.5.45, 5.6.26 and 5.7.6 requirements SSL connection must be established by default if explicit option isnt set. For compliance with existing …

四元素的真面目..........简单粗暴

作者&#xff1a;Yang Eninala 链接&#xff1a;https://www.zhihu.com/question/23005815/answer/33971127 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 根据我的理解&#xff0c;大多数人用汉密尔顿四元数就只…

2.自定义变量调节器

① 使用registerPlugin()方法来扩充变量调节器 该方法接收3个参数 1. 字符串modifier 2. 插件函数的名字 3. PHP回调函数 示例&#xff1a;自定义一个变量调节器&#xff0c;可以改变文字的颜色和大小 第一步&#xff1a;调用smarty对象的registerPlugin&#xff08;&#x…

SpringBoot2构建基于RBAC权限模型的驾校代理小程序后端

本项目是使用SpringBoot2构建的一套基于RBAC权限模型的后台管理系统&#xff0c;前端是微信小程序。 项目地址: github.com/fuyunwang/D… 项目的缘由 最近接了个外包,主要是针对于驾校开发一个代理小程序。目的是为了方便驾校的管理来招揽学员,同时方便维护学员和代理信息。 项…

while read line的问题

循环中的重定向或许你应该在其他脚本中见过下面的这种写法&#xff1a;while read linedo…done < file刚开始看到这种结构时&#xff0c;很难理解< file是如何与循环配合在一起工作的。因为循环内有很多条命令&#xff0c;而我们之前接触的重定向都是为一条命令工作的。…

Linemod;理解

Linemod 代码笔记 2019年03月11日 16:18:30 haithink 阅读数&#xff1a;197 最近了解到 Linemod 这个模板匹配算法&#xff0c;印象不错 准备仔细学习一下&#xff0c;先做点代码笔记&#xff0c;免得后面不好回顾 目前的笔记基本上把 核心流程都分析得比较清楚了&#xff0…

Swift3中数组创建方法

转载自&#xff1a;http://blog.csdn.net/bwf_erg/article/details/70858865 数组是由一组类型相同的元素构成的有序数据集合。数组中的集合元素是有 序的&#xff0c;而且可以重复出现。 1 数组创建 在Swift语言中&#xff0c;数组的类型格式为&#xff1a; Array<ElementT…

BZOJ 5249: [2018多省省队联测]IIIDX(贪心 + 线段树)

题意 这一天&#xff0c;\(\mathrm{Konano}\) 接到了一个任务&#xff0c;他需要给正在制作中的游戏 \(\mathrm{《IIIDX》}\) 安排曲目 的解锁顺序。游戏内共有\(n\) 首曲目&#xff0c;每首曲目都会有一个难度 \(d\) &#xff0c;游戏内第 \(i\) 首曲目会在玩家 Pass 第 \(\lf…

手眼标定

Eye-in-hand和Eye-to-hand问题求解和实验 2018年12月07日 00:00:40 百川木易 阅读数 3018 2018/12/5 By Yang Yang&#xff08;yangyangipp.ac.cn&#xff09; 本文所有源码和仿真场景文件全部公开&#xff0c;点击Gitee仓库链接。 文章目录 问题描述Eye-in-hand问题求解公式…

RNN总结

RNN既可以表述为循环神 经网络&#xff08;recurrent neural network&#xff09;&#xff0c;也可以表述为递归神经网络&#xff08;recursive neural network&#xff09;&#xff0c;前者一般用于处理以时间序列为输入的问题&#xff08;比如把一个句子看成词组成的序列&…

Problem 2. number题解

number&#xff1a;数学二分图匹配 首先&#xff0c;如果S<N,那么S1&#xff0c;S2...N这些数直接放在S1,S2...N的位置上(如果其他数x放在这些位置上面&#xff0c;这些数不放在对应位置&#xff0c;那么x一定能放在这些数放的位置&#xff0c;所以直接交换即可)所以可以直接…

SSD列子

一、介绍 本博文主要介绍实现通过SSD物体检测方式实现工件裂纹检测。裂纹图像如下所示&#xff1a; 二、关于SSD算法 具体算法不再阐述&#xff0c;详细请参考&#xff1a; https://blog.csdn.net/u013989576/article/details/73439202 https://blog.csdn.net/xiaohu2022/arti…

linux硬链接与软链接

Linux 系统中有软链接和硬链接两种特殊的“文件”。 软链接可以看作是Windows中的快捷方式&#xff0c;可以让你快速链接到目标档案或目录。 硬链接则透过文件系统的inode来产生新档名&#xff0c;而不是产生新档案。 创建方法都很简单&#xff1a; 软链接&#xff08;符号链接…

int转时间

int转时间 public static string FormatDuration(int duration) { if (duration 0) return "00:00:00"; int hours duration / 3600; int minutes duration % 3600 / 60; int seconds duration % 3600 % 60; string _hours hours.ToString("00") &qu…

企业级区块链现状研究报告:小企业的投资总额是大企业的28倍

根据企业级区块链现状研究报告表明&#xff0c;当前企业采用区块链技术的势头正在逐步增强。参与该报告的企业表示&#xff0c;区块链投资今年共增长了 62% &#xff0c;预计到 2025 年区块链将成为主流技术。其中&#xff0c;有 28% 的企业正在积极开展区块链发展计划。现在看…

特征匹配

Python 使用Opencv实现图像特征检测与匹配 2018-06-13 11:36:58 Xy-Huang 阅读数 19203更多 分类专栏&#xff1a; Python 人工智能 版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接…

bzoj 1015 并查集

代码&#xff1a; //这题可以反着想&#xff0c;把要去掉的点倒着处理变成往图中一个一个的加点&#xff0c;然后用并查集处理联通快就好了。 #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const in…