博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Head First 设计模式》之观察者模式
阅读量:5836 次
发布时间:2019-06-18

本文共 7121 字,大约阅读时间需要 23 分钟。

前言

  昨天lz写了一篇关于策略模式的文章,感觉这篇文章写了很久才完成,而且自我感觉写的并不是很好。究其原因lz发现有以下几点。第一,lz对设计模式刚开始接触,现在也仅仅只是停留在概念阶段,没有付诸实践,没有将这些设计理论运用到项目中去,可能现在对lz来讲很难讲其吃透,不过这也能理解,对新知识的学习毕竟是要循序渐进。第二,lz觉得自己的写作能力有所欠缺,高中语文确实是没学好呃,这个只能慢慢改善了。

  关于写博客这件事,lz看到一句话觉得说的很合理,故献给大家望共勉。“当别人请我给他们一些写 blog 的建议,我总是回他:挑个你自认为可以的时间行程安排,什么时候开始写 blog,预计多久写一篇文,开始动工,并坚持下去。在你这么做之前,任何建议对你来说都是不重要的。你文章是否写得很糟糕不重要,是否没有任何人会看你的 blog 不重要,是不是没啥有趣的东西可以记录也不重要。重要的是,只要你能透过写文来表现出写作的意愿,而且渴望持续地写作,检视、思考与改善自己的写作,你终究会成功的。”

今日分享

  正如之前写到的一样,这块内容以后每篇文章前面都会推送给大家。今天给大家带来了两句话。

  1.该舍的,舍不得,只顾着跟往事瞎扯,等你发现时间是贼了,它早已偷光你的选择!

  2.一句英文,Life is like a ball, your initial steps of the church who may not be able to accompany you come to finish. 人生就像一场舞会,教会你最初舞步的人,未必能陪你走到散场。不乱于心,不困于情,不畏将来,不念过往。“如果微笑成为习惯,快乐也会成为习惯”

观察者模式

  观察者模式是JDK中使用最多的模式之一,比如我们常用的java.util包,JavaBeans和Swing中,后续我们再做进一步介绍。可通俗点理解该模式为:能让你的对象知悉现况,不会错过该对象感兴趣的事情。

  认识观察者模式

  首先看看报纸和杂志的订阅是怎么回事:

  1.报社的业务就是出版报纸。

  2.向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。你要你是他们的订户,你就会一直受到新报纸。

  3.当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。

  4.只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消报纸。

我想大家从上面的这份关系中可以初步了解观察者模式,其实出版者+订阅者=观察者模式。不过我们习惯将出版者称为“主题”(Subject),订阅者称为“观察者”(Observer)。现用浅显的话语解释下,首先主题对象管理着某些数据,观察者已经订阅(注册)主题以便在主题数据改变时能够收到更新。其次当主题内的数据改变时,就会通知观察者,也即:新的数据会以某种形式送到观察者手上。当然,如果某个对象不是观察者,即使主题数据更新时也不会将新的数据通知到此对象。

  定义观察者模式

  现给出观察者模式官方解释:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。可以理解为,主题和观察者定义了一对多关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。根据通知的风格,观察者可能因此新值而更新。其实实现观察者模式的方法不止一种,但是以包含Subject和Observer接口的类设计的做法最为常见,下面给出该模式类图。

  UML类图

  气象站实例

  现给出具体需求:某公司需要建立下一代气象站,且必须建立在给出的WeatherData对象上,由该对象负责追踪目前的天气状况(温度,湿度,气压)。希望能建立一个应用,有三种布告板,分别显示目前的状况,气象统计及简单的预报。当WeatherData对象获得最新的测量数据时,三种布告板必须要实时更新。最后这是一个可扩展的气象站,也即:希望能实现自己的布告板并插入到此应用中。

  现给出该应用UML图:

下面我们再来具体实现该气象站,首先从接口开始,

主题接口:

1 package xin.yangmj.observer.subject; 2  3 import xin.yangmj.observer.observe.Observer; 4  5 /** 6  * 这是主题接口,所有具体主题都应实现此接口 7  * 8  * @author Eric Yang 9  * @create 2017-10-07 下午3:5610  **/11 public interface Subject {12 13     public void registerObserver(Observer o);14     public void removeObserver(Observer o);15     public void notifyObserver();16 }

观察者接口:

1 package xin.yangmj.observer.observe; 2  3 /** 4  * 这是观察者接口,所有具体观察者都应实现此接口 5  * 6  * @author Eric Yang 7  * @create 2017-10-07 下午4:00 8  **/ 9 public interface Observer {10 11     public void update(float temp, float humidity, float pressure);12 }

布告板接口,也即:具体布告板要实现此接口:

1 package xin.yangmj.observer.observe; 2  3 /** 4  * 这是布告板接口,用来展示获取到的数据 5  * 6  * @author Eric Yang 7  * @create 2017-10-07 下午4:06 8  **/ 9 public interface DisplayElement {10 11     public void display();12 }

然后,在写出具体的实现类

首先是具体主题实现类:

1 package xin.yangmj.observer.subject.impl; 2  3 import xin.yangmj.observer.observe.Observer; 4 import xin.yangmj.observer.subject.Subject; 5  6 import java.util.ArrayList; 7 import java.util.List; 8  9 /**10  * 这是WeatherData类,实现主题接口11  *12  * @author Eric Yang13  * @create 2017-10-07 下午4:0814  **/15 public class WeatherData implements Subject {16 17     // 用来封装主题所管理的观察者18     private List
observers;19 private float temperature;20 private float humidity;21 private float pressure;22 23 public WeatherData() {24 this.observers = new ArrayList
();25 }26 27 /**28 * 用于注册观察者到该主题中29 *30 * @param o31 */32 public void registerObserver(Observer o) {33 observers.add(o);34 }35 36 /**37 * 若观察者想取消注册,则调用该方法38 *39 * @param o40 */41 public void removeObserver(Observer o) {42 43 int i = observers.indexOf(0);44 if (i >= 0) {45 observers.remove(i);46 }47 }48 49 /**50 * 通知观察者,将主题最新数据告知每个注册的观察者51 */52 public void notifyObserver() {53 54 for (Observer observer : observers) {55 observer.update(temperature, humidity, pressure);56 }57 }58 59 /**60 * 当从气象站得到更新观测值时,通知观察者61 */62 public void measurementsChanged() {63 notifyObserver();64 }65 66 /**67 * 动态改变观测值68 *69 * @param temperature70 * @param humidity71 * @param pressure72 */73 public void setMeasurements(float temperature, float humidity, float pressure) {74 this.temperature = temperature;75 this.humidity = humidity;76 this.pressure = pressure;77 }78 79 // WeatherData的其他方法80 }

给出某一个布告板实现类:

1 package xin.yangmj.observer.observe.impl; 2  3 import xin.yangmj.observer.observe.DisplayElement; 4 import xin.yangmj.observer.observe.Observer; 5 import xin.yangmj.observer.subject.Subject; 6  7 /** 8  * 具体布告板,相当于具体观察者实现类 9  *10  * @author Eric Yang11  * @create 2017-10-07 下午4:2812  **/13 public class CurrentConditionsDisplay implements Observer, DisplayElement{14 15     private float temperature;16     private float humidity;17     private Subject weatherData;18 19     /**20      * 通过构造器,可以将此观察者注册到主题中21      *22      * @param weatherData23      */24     public CurrentConditionsDisplay(Subject weatherData) {25         this.weatherData = weatherData;26         weatherData.registerObserver(this);27     }28 29     /**30      * 当观测值更新时,将最新数据保存起来31      *32      * @param temperature33      * @param humidity34      * @param pressure35      */36     public void update(float temperature, float humidity, float pressure) {37         this.temperature = temperature;38         this.humidity = humidity;39         display();40     }41 42     /**43      * 在该布告板上展示最新的观测值数据44      */45     public void display() {46         System.out.println("Current conditions: " + temperature +47                 "F degrees and " + humidity + "% humidity");48     }49 }

启动气象站,测试用例:

1 package xin.yangmj.observer; 2  3 import xin.yangmj.observer.observe.impl.CurrentConditionsDisplay; 4 import xin.yangmj.observer.subject.impl.WeatherData; 5  6 /** 7  * 测试类,可用于启动气象站 8  * 9  * @author Eric Yang10  * @create 2017-10-07 下午4:3911  **/12 public class WeatherStation {13 14     public static void main(String[] args){15 16         // 创建具体主题,并初始化所管理的观察者为空17         WeatherData weatherData = new WeatherData();18 19         // 暂时只写一个面板,其他类似eg:StatisticsDisplay, ForecastDisplay等20         // 也可以后续扩展,实现自己特定的面板21         // 创建该观察者,隐含了将该观察者注册到上面具体主题中22         CurrentConditionsDisplay currentConditionsDisplay =23                 new CurrentConditionsDisplay(weatherData);24 25         weatherData.setMeasurements(80, 65, 30.4f);26         // 通知观察者27         weatherData.notifyObserver();28         // 测量值发生变化29         weatherData.setMeasurements(82, 70, 29.3f);30         weatherData.measurementsChanged();31     }32 }

运行结果:

OK,以上就是整个气象站应用的代码。现对整个应用做个总结如下

  设计原则

  观察者模式遵循了以下几个设计原则:

  1.为了交互对象之间的松耦合而努力。也即:让主题和观察者之间松耦合。关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口),主题不需要知道观察者的具体类是谁,做了些什么或其他任何细节。有新类型的观察者出现时,主题的代码不需要修改,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。我们可以独立地复用主题或观察者,改变主题或观察者其中一方,并不会影响另一方,所以二者是松耦合的。

  2.封装变化。在此模式中,会改变的是主题的状态,以及观察者的数目是类型。用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题,也即:提前规划。

  3.针对接口编程。主题和观察者都是用接口:观察者利用主题的接口想主题注册,而主题利用观察者接口通知观察者。这样可以让二者之间运作正常,又同时具有松耦合的有点。

  4.多用组合,少用继承。该模式利用“组合”将许多观察者组合进主题中。对象之间的这种关系不是通过继承产生的,而是在运行时利用组合的方式来产生的。

  使用Java内置的观察者模式

  未完待续...  

  

  

 

转载于:https://www.cnblogs.com/yangmengjie/p/7634804.html

你可能感兴趣的文章
何如获取单选框中某一个选中的值
查看>>
paip.输入法编程----删除双字词简拼
查看>>
tcp状态
查看>>
QQ悬浮返回顶部
查看>>
MySQL建表语句的一些特殊字段
查看>>
《Unix环境高级编程》读书笔记 第8章-进程控制
查看>>
腾讯前端二面题目详解
查看>>
mascara-1
查看>>
Jquery Form表单取值
查看>>
Python version 2.7 required, which was not found in the registry
查看>>
Android API level 与version对应关系
查看>>
Team Name
查看>>
String类
查看>>
西门子_TDC_数据耦合小经验
查看>>
接口测试与postman
查看>>
mac zsh选择到行首的快捷键
查看>>
LINQ To XML的一些方法
查看>>
[LeetCode] Copy List with Random Pointer
查看>>
openstack部署之nova
查看>>
JS组件系列——表格组件神器:bootstrap table
查看>>