head first 设计模式之---------观察者模式
来源:互联网 发布:淘宝刷客收入揭秘 编辑:程序博客网 时间:2024/05/20 19:49
一、观察者模式 定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。
如何更好 理解???
二、观察者模式的组成
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角
色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
2.1*强调内容* 观察者模式原型
2.2观察者实现方式
1.主题主动推送数据
当数据更新后,主题会将所有更新数据都推送给观察者,而观察者只能被动接受主题的推送信息。
2.观察者主动拉取数据
当数据更新后,主题会通知观察者数据更新了,并暴露出相关数据的getter方法,观察者们可根据自己的需要去拉取自己需要的信息。
2.3具体举例来说明:
目前我们需要实现一种天气实时更新的程序(天气推送),当气象站数据更新后,天气接口程序去获取最新天气数据,然后将数据分发给所有订阅过“天气日报”程序的用户,即使更新数据。
(案例来源于《Head First 设计模式》)
整体结构图:
由上图可以看出,气象站负责去检测天气情况,当数据发生变化时,天气服务获取了变化的数据并且需要将数据分发给众多订阅“天气推送”的用户,如果我们采用一个个去通知的形式去实现的话,那么当我们新增了一个观察者,我们又需要单独重复编写发布信息代码,当我们想去掉一个观察者的时候,又需要去删减部分代码,这样的操作实在很繁琐,耦合度也比较高。接下来我们采用观察者模式来实现这个需求,来看看有没有什么神奇的地方。
两种方式的代码实现
方式一:主题推送数据
这里我们采取自己编写抽象主题与抽象观察者代码的方式来实现。
抽象主题:SubjectInterface.java
package observer.one.subject;import observer.one.observers.ObserverInterface;public interface SubjectInterface { public void registerObserver(ObserverInterface o); public void removeObserver(ObserverInterface o); public void notifyObservers();}
具体主题:WeatherData.java
package observer.one.subject.impl;import java.util.ArrayList;import observer.one.observers.ObserverInterface;import observer.one.subject.SubjectInterface;public class WeatherData implements SubjectInterface{ private ArrayList<ObserverInterface> observers; //温度 private String temperature; //湿度 private String humidity; //气压 private String pressure; public WeatherData() { observers=new ArrayList<ObserverInterface>(); } /** * 订阅 */ public void registerObserver(ObserverInterface o) { observers.add(o); } /** * 取消订阅 */ public void removeObserver(ObserverInterface o) { if(observers.indexOf(o)>=0){ observers.remove(o); } } /** * 通知观察者 */ public void notifyObservers() { for(ObserverInterface o:observers){ o.update(temperature, humidity, pressure); } } public void setDataChange() { notifyObservers(); } /** * 数据改变后,通知观察者 * @param temperature * @param humidity * @param pressure */ public void setNewData(String temperature,String humidity,String pressure){ this.temperature=temperature; this.humidity=humidity; this.pressure=pressure; setDataChange(); }}
抽象观察者:ObserverInterface.java
package observer.one.observers;public interface ObserverInterface { void update(String temperature,String humidity,String pressure);}
实际上,我们看到这里就会发现有点问题,一旦我们的数据参数发生变化,就需要去修改抽象观察者方法,而具体观察者也需要去修改相关方法的实现,耦合性较大。
具体观察者:Observer1.java
package observer.one.observers.impl;import java.util.Date;import observer.one.observers.ObserverInterface;import observer.one.subject.SubjectInterface;public class Observer1 implements ObserverInterface{ private SubjectInterface subject; //温度 private String temperature; //湿度 private String humidity; //气压 private String pressure; public Observer1(SubjectInterface subject) { this.subject = subject; subject.registerObserver(this); } public void register(){ System.out.println("------观察者1订阅成功-------"); subject.registerObserver(this); } public void cancelRegister(){ System.out.println("------观察者1取消订阅了-------"); subject.removeObserver(this); } public void update(String temperature, String humidity, String pressure) { this.humidity=humidity; this.pressure=pressure; this.temperature=temperature; display(); } private void display() { System.out.println("观察者1----数据更新了("+new Date()+")-温度:"+temperature+"-湿度:"+humidity+"-气压:"+pressure); }}
测试方法:
这里为了方便演示,我写了两个具体观察者(Observer1 ,Observer2 ),实际上在具体实现中只需要写一个,实例化多个即可。
package observer.one;import observer.one.observers.impl.Observer1;import observer.one.observers.impl.Observer2;import observer.one.subject.impl.WeatherData;public class Test { public static void main(String[] args) { WeatherData weatherData=new WeatherData(); //订阅天气日报 Observer1 observer1=new Observer1(weatherData); //订阅天气日报 Observer2 observer2=new Observer2(weatherData); weatherData.setNewData("10", "20", "30"); observer1.cancelRegister(); weatherData.setNewData("10.5", "14.23", "15.65"); observer1.register(); weatherData.setNewData("15.5", "18.23", "17"); }}
输出结果:
方式二:观察者主动拉取数据
这里我们采取JDK自己提供的抽象主题与抽象观察者的方式来实现。
抽象主题:java.util.Observable
抽象观察者:java.util.Observer
具体主题:WeatherData.java
package observer.two.subject;import java.util.Observable;public class WeatherData extends Observable{ //温度 private String temperature; //湿度 private String humidity; //气压 private String pressure; /** * 数据更新方法 * @param temperature * @param humidity * @param pressure */ public void setNewData(String temperature,String humidity,String pressure){ this.temperature=temperature; this.humidity=humidity; this.pressure=pressure; setChanged(); notifyObservers("数据更新了,快来获取吧"); } public String getTemperature() { return temperature; } public String getHumidity() { return humidity; } public String getPressure() { return pressure; }}
由上面代码可以看出,具体主题主动暴露出属性的getter方法,当数据更新时调用setChange()方法,通知观察者此时有数据更新,你可以来获取了。
具体观察者:Observer1.java
package observer.two.observers;import java.util.Date;import java.util.Observable;import java.util.Observer;import observer.two.subject.WeatherData;public class Observer1 implements Observer{ private Observable observable; //温度 private String temperature; //湿度 private String humidity; //气压 private String pressure; public Observer1(Observable observable) { super(); this.observable = observable; System.out.println("------观察者1订阅了-------"); observable.addObserver(this); } public void cancelRegister(){ System.out.println("------观察者1取消订阅了-------"); observable.deleteObserver(this); } /** * 数据更新通知 */ public void update(Observable o, Object arg) { System.out.println("气象台说:"+arg+""); System.out.println("观察者1:嗯,这就去"); if(o instanceof WeatherData){ WeatherData data=(WeatherData)o; this.humidity=data.getHumidity(); this.pressure=data.getPressure(); this.temperature=data.getTemperature(); } display(); System.out.println("数据提取完毕,并已展示"); } /** * 数据打印 */ private void display() { System.out.println("观察者1----数据更新了("+new Date()+")-温度:"+temperature+"-湿度:"+humidity+"-气压:"+pressure); }}
此时,具体观察者调用update方法,主动拉取主题的最新数据,并显示出来。
测试方法:
package observer.two;import observer.two.observers.Observer1;import observer.two.subject.WeatherData;public class Test { public static void main(String[] args) { WeatherData weatherData=new WeatherData(); /*观察者1订阅天气日报*/ Observer1 observer1=new Observer1(weatherData); Observer1 observer2=new Observer1(weatherData); weatherData.setNewData("10", "79", "18"); }}
输出结果:
两种实现方式对比
细心的同学应该可以发现,自己编写抽象主题代码时,我们编写的接口(interface),而JDK官方提供的观察者模式中,抽象主题采用的是继承的形式实现。归根结底这两种实现方式的对比,是主题推送数据和观察者拉取数据的对比,以及实现接口和继承父类的对比。
推送数据和拉取数据的对比:
推送数据的实现方式主题需要把所有的参数都推送给观察者们,这里就需要事先在update方法中指定所有的参数,一旦参数发生改变,不仅要改变主题的方法,还需要改变观察者接口方法。
而拉取数据的实现方式只需要改变主题参数,不需要改变观察者接口方法,观察者们依旧根据自己的需要去获取数据。
实现接口和继承父类的对比:
由于JAVA只支持单继承,实现接口和继承父类的优劣势大家也应该都很清楚。
对比结果:如果可以的话,我们应该自己去实现自己的抽象主题,而不采用JDK官方提供的实现方式,毕竟继承的形式有一定的弊端。在数据获取方面,最好采用具体观察者拉取的形式,这样更有利于后期进行扩展。
相关文章:《设计模式——策略模式:会员价格体系的简单实现》
案例转载于https://my.oschina.net/visionit/blog/758673
- 《Head First 设计模式》之观察者模式
- 《Head First 设计模式》之观察者模式
- head first设计模式之观察者模式
- head first 设计模式之---------观察者模式
- java设计模式-Head First设计模式之观察者模式
- 《Head First设计模式》读书笔记之观察者模式
- Head First设计模式之观察者,装饰者模式
- 《Head First 设计模式》读书笔记之观察者模式
- 《Head First 设计模式》学习笔记之观察者模式
- Head First设计模式之观察者模式(Observer Pattern)
- 学习head first 设计模式之观察者模式
- head first 设计模式:观察者模式1
- Head First设计模式-观察者模式
- 《Head First 设计模式》观察者模式
- Head First 设计模式笔记--观察者模式
- Head First 设计模式2 观察者模式
- <Head First 设计模式>:观察者模式--Weather
- Head First设计模式—观察者模式
- netsh的基本应用----修改本机的ip
- jira 6.0.3 破解 && 汉化(反编译实例讲解)
- 设计模式(八)装饰器模式Decorator(结构型)
- javascript-MDN学习笔记-Array部分
- Docker构建SpringBoot镜像
- head first 设计模式之---------观察者模式
- SQLServer2016 AlwaysOn基于证书的搭建笔记
- ICCV2013-Hybrid Deep Learning for Face Verification
- eclipse控制台中输入中文输出乱码的解决办法http://jxtm.bsdlover.cn/?p=1425
- mediator 中介者模式
- iOS 单元格选中之后返回的时候不再显示选中状态
- Android基础-1 基于Eclipse的开发环境搭建
- DrawerLayout布局的使用步骤
- Golang语言常用算法