headfirst设计模式(2)—观察者模式
定义
观察者模式(有时又被称为发布(publish)-订阅(Subscribe)模式,在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统(摘自百度百科)。
关键词:发布-订阅
为什么只有一个关键词?因为我觉得一个关键词足够说明问题了。观察者模式适用于,一个对象改变时,需要通知一个或多个其他对象,而需要通知的对象的特点是:数量不清楚,类型不清楚(仅实现了一个通用接口),具体处理方式不清楚。
举个例子来说明:
小花:你好,我开发过很多erp系统,是一位经验丰富的女司机,现在想找一份java程序员的工作...(成熟稳重型)
猎头:好的,我已经把你加入到我的程序员清单里面了,不要打电话给我,我会通知你的(好莱坞原则)
小明:本人学识渊博、经验丰富,代码风骚、效率恐怖,c/c++、java、php无不精通,熟练掌握各种框架,深山苦练20余年,一天只睡4小时,电话通知出bug后秒登vpn,千里之外定位问题,瞬息之间修复上线。 身体强壮、健步如飞,可连续编程100小时不休息,讨论技术方案5小时不喝水,上至带项目、出方案,下至盗账号、威胁pm,什么都能干......(花式装逼型)
一个气象监测应用的需求
package observer; /*** 观察主题*/ public interface Observable{public void addObserver(Observer observer);//添加观察者public void removeObserver(Observer observer);//移除观察者public void notifyObservers(WeatherData data);//通知所有观察者 }
观察主题也可以是抽象类,具体可以参考java.util.Observable,这里就不展开来bb了。
那么什么时候选择抽象类,什么时候选择接口呢?
我的理解是,这个就要看,代价高不高了,抽象类的好处就是,可以少写代码,实现复用。接口可以应对各种不同的变化,因为观察者并不一定有共同使用的实现类,可能它们完全就是不同的东西。
这个地方我只有一个主题,我想用什么就用什么,就是这么任性,如果以后出了第二个或者第三个主题,那么就可以考虑具体是抽象类还是接口了,当然也不排除两种都用的情况。当然这是后话,程序本来就是不断变化的,适当的时候用适当的设计才是王道。
package observer; /*** 观察者*/ public interface Observer {public abstract void update(WeatherData data); }
package observer; /*** 天气数据*/ public class WeatherData {private float temperature;private float humidity;private float pressure;public WeatherData(){}public WeatherData(float temperature, float humidity, float pressure){this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;} }
getter,setter省略,不然篇幅太长了
在Observer这个接口里面,我的update()方法里面带了一个 WeatherData对象,为什么不是Object呢,为什么不是直接三个参数,温度,湿度,气压呢?我当时想了很久(我也是一边看书,一遍写的,不是把所有的都学完了才来写博客的,所以不懂的多了去了)
用Object的好处当然是不仅更新天气可以用这个,以后更新其他什么的也可以用,而且,如果我update方法里面的需求有了新的变化,比如,我要更新时间,那么,这个参数总不能放在WeatherData里面吧,好不符合逻辑啊,强迫症怎么受得了???
思来想去我的理解是这样的:
1,这个是一个气象站应用,那么应该就是存气象数据吧,这个总没问题嘛
2,写一个Object会不会被后面接替我工作的同事砍死啊,Object里面是什么,通过方法名根本就看不出来,必须去具体的代码里面看,万一我逻辑有点复杂,注释再少点,那他不就懵逼了?
3,不直接用三个参数也是为了以后的变化,万一变成5个参数咋办?改都改死人,而且要是5个都是float类型,好容易在传的时候传错,发现得早还好,万一传错了,但是又通过测试了怎么办呢?
肯定有人觉得这不可能,那我举个例子
接口的定义是:
void test(int a, int b, int c);
实现是 void test(int a, int c, int b){...}
调用接口的时候,传入的是test.test(a, c, b);那么请问,这个能通过测试吗?可以的。后面的人会掉坑里吗?我觉得他只要去改代码,那么就很有可能,嘿嘿嘿
package observer; /*** 显示*/ public interface DisplayElement {void display(); }
这个接口没什么解释的,就是显示用的,下面我要大段贴代码了
package observer; /*** 当前天气状况*/ public class CurrentConditionsDisplay implements DisplayElement, Observer {Observable observable;public CurrentConditionsDisplay(Observable observable) {this.observable = observable;}WeatherData data = new WeatherData();@Overridepublic void display() {System.out.println("当前的天气状况: " + "温度(℉):" + data.getTemperature() + " " + "湿度:" + data.getHumidity() + " " +"气压:" + data.getPressure());}@Overridepublic void update(WeatherData data) {this.data = data;display();} }
package observer; /*** 天气统计**/ public class StatisticsDisplay implements DisplayElement, Observer {private Float average;private Float highest;private Float lowest;@Overridepublic void display() {System.out.println("天气统计:" +"平均温度(℉):" + average + " " +"最高温度(℉):" + highest + " " +"最低温度(℉):" + lowest);}@Overridepublic void update(WeatherData data) {float temperature = data.getTemperature();average = null == average ? temperature : (average + temperature) / 2;highest = null == highest ? temperature : (highest > temperature ? highest : temperature);lowest = null == lowest ? temperature : (lowest > temperature ? temperature : lowest);display();}}
package observer; /*** 天气预报*/ public class ForecastDisplay implements DisplayElement, Observer {private float pressure;@Overridepublic void update(WeatherData data) {pressure = data.getPressure();display();}@Overridepublic void display() {System.out.println("天气预测:" + forecast());}private static final float INFRABAR = 28.5f;//气压低就会下雨private String forecast(){return INFRABAR < pressure ? "明天不下雨" : "明天要下雨";} }
package observer; import java.util.ArrayList; import java.util.List; /*** 天气主题**/ public class Weather implements Observable {private List<Observer> observers = new ArrayList<>();;public void addObserver(Observer observer) {observers.add(observer);}public void removeObserver(Observer observer) {observers.remove(observer);}public void notifyObservers(WeatherData data) {for (Observer observer : observers)observer.update(data);} }
package observer; /*** 测试* @author Skysea**/ public class Client {public static void main(String[] args) {Observable observable = new Weather();Observer currentCondition = new CurrentConditionsDisplay(observable);Observer statistics = new StatisticsDisplay();Observer forecast = new ForecastDisplay();observable.addObserver(currentCondition);observable.addObserver(statistics);observable.addObserver(forecast);observable.notifyObservers(new WeatherData(80, 65, 30.4f));observable.notifyObservers(new WeatherData(82, 70, 29.2f));observable.notifyObservers(new WeatherData(78, 90, 25.1f));} }
运行结果:
在测试代码中,添加观察者到主题这些代码,也是可以放在观察者中去实现的,在初始化的时候就把自己加入到主题的列表中
在实际的使用中,如使用Spring的依赖注入之类的,还是很好用的,也可以省很多事情,最后的交互方式大概是这个样子
package observer; /*** 测试2*/ public class Client2 {@Autowiredprivate Observable observable;public static void main(String[] args) {observable.notifyObservers(new WeatherData(80, 65, 30.4f));observable.notifyObservers(new WeatherData(82, 70, 29.2f));observable.notifyObservers(new WeatherData(78, 90, 25.1f));} }
嗯,没错,什么初始化都没有了,观察者在启动的时候就注入到主题中了,只需要调用主题的接口就好了,而主题也仅仅是持有了一个List<Observer> observers;具体的观察者是谁它也不知道,但是它们还是可以相互交互,是不是很酷?
好了,我bb完了,本系列的大部分所有例子,都是在看headfirst设计模式时,看到的,并加入自己的理解写下来的(当然我也编了一些),写这段话的目的也是为了避免一些不必要的误会,以后的每期我都会复制这段话,哈哈哈
转载于:https://www.cnblogs.com/skyseavae/p/6379293.html
headfirst设计模式(2)—观察者模式相关推荐
- HeadFirst设计模式之观察者模式学习
一.观察者模式的定义: 观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者,都会收到通知并自动更新. 二.我个人对于观察者模式的理解: 当主题发生改变时,自动通知到所有观察者, ...
- 【HeadFirst设计模式——开篇】
近期在看HeadFirst,接下来的一段时间会陆续更新有关HeadFirst设计模式相关的文章.记得非常久之前在学习大话设计模式的时候,仅仅是走马观花的大致走过一遍.至于里面非常多东西都掌握的不是非常 ...
- HeadFirst设计模式(模式总览速查)
本文用于记录本人阅读完HeadFirst设计模式一书后对此书的总结,总结系个人理解并简化提炼,方便使用设计模式时速查,如有错漏,请积极指出,本人将虚心接受并及时改正. 1. 策略模式 1.1 使用前提 ...
- 设计模式:观察者模式--Observer
一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...
- Headfirst设计模式的C++实现——策略模式(Strategy)
前言 最近在学习<Headfirst设计模式>,里面的例子都是Java的.但是我对Java并不熟悉,所以试着用C++来实现书中的例子. 先来看看Duck以及子类 Duck.h 1 #inc ...
- Delphi 设计模式:《HeadFirst设计模式》Delphi代码---模式小结之一个叫声接口和几只鸭子[转]...
一.一个叫声接口和几只鸭子 从一个叫声接口开始. {<HeadFirst设计模式>Delphi代码之模式小结 } { 一个叫声接口 } ...
- java 观察者模式_图解Java设计模式之观察者模式
图解Java设计模式之观察者模式 天气预报项目需求 天气预报设计方案 1 - 普通方案 观察者模式(Observer)原理 观察者模式解决天气预报需求 观察者模式在JDK应用的源码分析 天气预报项目需 ...
- 游戏服务器架构-设计模式之观察者模式和发布订阅模式真的一样吗?
前面我给大家分享了观察者模式和发布订阅模式,有人私信给我说这俩不是一样嘛,大体没什么区别,我猜测大多数认为这两者是一样的可以继续阅读这两篇文章,如果还不能解答你的问题,我相信这篇文章对比两者的关系会让 ...
- Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---模板方法模式之CoffeineBeverageWithHook[转]...
模板方法模式定义了一个算法骨架,允许子类对算法的某个或某些步骤进行重写(override). 1 2{<HeadFirst设计模式>之模板方法模式 } 3{ 编译工具: Del ...
最新文章
- 阿里PB级Kubernetes日志平台建设实践
- 【js笔记】数组那些事[0]
- 了解C++类的大小和类变量的字节对齐
- hello2 source analysis
- 选择 Reac​​tJS 的五大理由
- mpvue 小程序 页面跳转获取参数
- NSURLCache缓存使用简介
- 在lighttpd上使用fastcgi方式部署hg server
- 【Oracle学习笔记】常用知识梳理
- 求树的直径+并查集(bfs,dfs都可以)hdu4514
- js中addEventListener第三个参数涉及到的事件捕获与冒泡
- python调用r语言函数_让R与Python共舞
- antd源码解读(6)- Affix
- python贴吧签到多账号版本最新可用
- 邮箱服务器退回,126邮箱群发邮件被对方服务器退回
- 直通车执行营销方式方法
- 高考改革后计算机老师,高考改革“漏洞”多?2020新高考选科数据曝光!这是选科最佳组合...
- win10辅助准星教程
- python expend_Python序列化proto中repeated修饰的数据
- 二进制炸弹实验bomb-whu 拆弹
热门文章
- 数据库主从延迟导致查询不准确的解决思路
- 惹怒程序员的下场!阿里达摩院大神受不了骚扰电话,业余发起“二哈”AI,315后爆红...
- 捡漏!用谷歌图片搜索自制深度学习数据集 | 教程
- 十个优衣库仓库理货员,只有一个能留下,机器已经上岗了
- 什么才是一份好的AI求职简历?
- 提到强化学习只知道AlphaGo?其实,RL在工业界还有这些应用
- 寒假作业3:抓老鼠啊~亏了还是赚了?
- nginx 的 proxy_cache 缓存配置
- C# devexpress gridcontrol 分页 控件制作
- java方法:flush()