JAVA设计模式之观察者模式
2018-02-05 10:58
399 查看
观察者模式是日常开发中最为常用的设计模式之一,本文主要分为四个部分:1、什么是观察者模式 2、观察者模式由哪些组件构成 3、使用观察者模式实现天气预报布告栏的案例 4、使用JDK内置的观察者模式实现天气预报布告栏的案例。
在现实生活中,可以找到很多跟观察者模式有关的例子,比如说猎头和求职者之间就是一种一对多的关系,有一个猎头,求职者们可以在他那儿登陆注册,留存简历,当猎头发现有合适的工作时会将应聘信息发送给这些人,求职者可以随时跟猎头建立或者取消合作关系,一旦取消合作关系,猎头就不会再发送应聘信息给对应的求职者,这其中猎头就扮演一种有状态的对象,而求职者就是依赖猎头的对象,他们是一对多的关系。
上图中,Subject是一个主题接口,接口中包含注册观察者、移除观察者、通知观察者这三个基本事件,每个具体的主题都应该去实现这个接口,重写其中的方法。Observer是观察者接口,与主题是多对一的关系,观察者的核心方法是update方法,根据主题发生的变化,自动更新自己的状态。
目前天气布告栏
格式为:今天天气(晴朗/多云/有雨/有雪)
气压温度布告栏
格式为:今天气压(XX)Pa,温度(XX)摄氏度
明天天气预报布告栏
格式为:明天天气(晴朗/多云/有雨/有雪)
这个案例中,我们可以把天气预报的数据看成是主题对象Subject,包含了天气的详细信息,而三个布告栏就是观察者Observers,Subject中天气信息的一旦变更会通知三个布告栏,布告栏调用自己的update方法来更新显示内容,这是一个典型的观察者模式,下面我们就用代码来实现这个案例。
// 主题接口
// 布告栏显示接口
// 观察者接口
// 天气数据主题类
// 温度气压布告栏
// 今天天气布告栏
// 测试类
运行结果
1. 上面的观察者更新的数据写死了,无法更改。
2. 主题对象将所有数据推送给观察者,但是有些数据并不是每个观察者都需要的。那么,主题对象是不是应该只通知观察者数据更新了,而具体需要什么数据,由各个观察者自己去主题对象那边取。
基于以上两个问题,我们可以做出进一步改进,不过这里就不自己动手写了,我们用JDK中封装好的观察者模式编写改进。
// WeatherData 主题类,继承Observable类
// TempAndPressureBoard 布告板
// 测试类
运行结果
什么是观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象的状态发生改变时,它的所有依赖者都会收到通知,并且做出改变。在现实生活中,可以找到很多跟观察者模式有关的例子,比如说猎头和求职者之间就是一种一对多的关系,有一个猎头,求职者们可以在他那儿登陆注册,留存简历,当猎头发现有合适的工作时会将应聘信息发送给这些人,求职者可以随时跟猎头建立或者取消合作关系,一旦取消合作关系,猎头就不会再发送应聘信息给对应的求职者,这其中猎头就扮演一种有状态的对象,而求职者就是依赖猎头的对象,他们是一对多的关系。
观察者模式由哪些组件构成
根据观察者模式的概念,我们很容易想到,观察者模式中的两种核心组件,即主题对象(Subject)和众多的观察者对象(Observer),一旦主题对象中的内容发生改变,观察者也要根据改变的内容对自己做出调整。因此观察者的UML类图可以简单描述为:上图中,Subject是一个主题接口,接口中包含注册观察者、移除观察者、通知观察者这三个基本事件,每个具体的主题都应该去实现这个接口,重写其中的方法。Observer是观察者接口,与主题是多对一的关系,观察者的核心方法是update方法,根据主题发生的变化,自动更新自己的状态。
观察者模式实现天气预报布告栏案例
通过一个实际的案例来运用一下观察者模式,一个天气预报发布平台有三种布告栏:目前天气布告栏
格式为:今天天气(晴朗/多云/有雨/有雪)
气压温度布告栏
格式为:今天气压(XX)Pa,温度(XX)摄氏度
明天天气预报布告栏
格式为:明天天气(晴朗/多云/有雨/有雪)
这个案例中,我们可以把天气预报的数据看成是主题对象Subject,包含了天气的详细信息,而三个布告栏就是观察者Observers,Subject中天气信息的一旦变更会通知三个布告栏,布告栏调用自己的update方法来更新显示内容,这是一个典型的观察者模式,下面我们就用代码来实现这个案例。
// 主题接口
public interface Subject { public void registerObserver(Observer observer); public void removeObserver(Observer observer); public void notifyObservers(); }
// 布告栏显示接口
// 布告栏信息显示,每个布告栏除了实现Observer接口,还需实现本接口 public interface DisplayElement { public void display(); }
// 观察者接口
public interface Observer { // 这个方法中的数据,原则上来说应该封装成一个对象,这里为了简单起见直接写死了 public void update(String todayWeather,Double pa, Double temp, String tomorrowWeather); }
// 天气数据主题类
import java.util.ArrayList; import java.util.List; public class WeatherData implements Subject { private List<Observer> observers; private String todayWeather; private Double pa; private Double temp; private String tomorrowWeather; public WeatherData(){ observers = new ArrayList<>(); } @Override public void registerObserver(Observer observer) { // 注册新的观察者 observers.add(observer); } @Override public void removeObserver(Observer observer) { int index = observers.indexOf(observer); if(index > -1) observers.remove(observer); } @Override public void notifyObservers() { //数据改动时通知各个观察者 for( Observer o : observers) o.update(todayWeather,pa,temp,tomorrowWeather); } public void dataChanged(){ notifyObservers(); } public void setNewData(String todayWeather,Double pa, Double temp, String tomorrowWeather){ this.todayWeather = todayWeather; this.pa = pa; this.temp = temp; this.todayWeather = tomorrowWeather; dataChanged(); } }
// 温度气压布告栏
public class TempAndPressureBoard implements Observer,DisplayElement{ private Double pa; private Double temp; private Subject weatherData; public TempAndPressureBoard(Subject weatherData){ this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("气压温度布告栏------》今天气压"+pa+"Pa,温度"+temp+"摄氏度"); } @Override public void update(String todayWeather, Double pa, Double temp, String tomorrowWeather) { this.pa = pa; this.temp = temp; display(); } }
// 今天天气布告栏
public class TodayWeatherBoard implements Observer,DisplayElement { private String todayWeather; private Subject weatherData; public TodayWeatherBoard(Subject weatherData){ this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("今天天气布告栏------》今天天气"+this.todayWeather); } @Override public void update(String todayWeather, Double pa, Double temp, String tomorrowWeather) { this.todayWeather = todayWeather; display(); } }
// 测试类
public class Test { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); TodayWeatherBoard todayBoard = new TodayWeatherBoard(weatherData); TempAndPressureBoard tempAndPressureBoard = new TempAndPressureBoard(weatherData); weatherData.setNewData("晴朗",5.0,25.0,"晴朗"); weatherData.setNewData("下雨",4.0,22.0,"下雪"); } }
运行结果
采用JDK内置的观察者模式实现天气预报布告栏案例
上面是我们自己动手实现的一个天气预报布告栏的案例,不过自己实现还有几个地方的细节没有处理好:1. 上面的观察者更新的数据写死了,无法更改。
2. 主题对象将所有数据推送给观察者,但是有些数据并不是每个观察者都需要的。那么,主题对象是不是应该只通知观察者数据更新了,而具体需要什么数据,由各个观察者自己去主题对象那边取。
基于以上两个问题,我们可以做出进一步改进,不过这里就不自己动手写了,我们用JDK中封装好的观察者模式编写改进。
// WeatherData 主题类,继承Observable类
import java.util.Observable; public class WeatherData extends Observable { private String todayWeather; private Double pa; private Double temp; private String tomorrowWeather; public void setNewData(String todayWeather,Double pa, Double temp, String tomorrowWeather){ this.todayWeather = todayWeather; this.pa = pa; this.temp = temp; this.todayWeather = tomorrowWeather; setChanged(); notifyObservers(); } public String getTodayWeather() { return todayWeather; } public void setTodayWeather(String todayWeather) { this.todayWeather = todayWeather; } public Double getPa() { return pa; } public void setPa(Double pa) { this.pa = pa; } public Double getTemp() { return temp; } public void setTemp(Double temp) { this.temp = temp; } public String getTomorrowWeather() { return tomorrowWeather; } public void setTomorrowWeather(String tomorrowWeather) { this.tomorrowWeather = tomorrowWeather; } }
// TempAndPressureBoard 布告板
import java.util.Observable; import java.util.Observer; public class TempAndPressureBoard implements Observer, DisplayElement{ private Double pa; private Double temp; public TempAndPressureBoard(Observable observable){ observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if( o instanceof WeatherData){ this.pa = ((WeatherData) o).getPa(); this.temp = ((WeatherData) o).getTemp(); display(); } } @Override public void display() { System.out.println("气压温度布告栏------》今天气压"+pa+"Pa,温度"+temp+"摄氏度"); } }
// 测试类
public class Test { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); TempAndPressureBoard tempAndPressureBoard = new TempAndPressureBoard(weatherData); weatherData.setNewData("晴朗",5.0,25.0,"晴朗"); weatherData.setNewData("下雨",4.0,22.0,"下雪"); } }
运行结果
相关文章推荐
- java设计模式_观察者模式
- Java设计模式--观察者模式
- Java设计模式——观察者模式
- Java开发中的23种设计模式详解----观察者模式(Observer)
- java设计模式--事件监听器模式和观察者模式 .
- Java设计模式-----Observer观察者模式
- java 观察者设计模式
- java设计模式15——观察者模式(Observer)
- Java设计模式之观察者
- Java设计模式之二--观察者模式
- Java/Android设计模式<二>观察者模式
- 【Java常用类库】_观察者设计模式笔记
- java设计模式_观察者模式
- JAVA设计模式之观察者模式
- Java设计模式之观察者模式
- 观察者设计模式 Vs 事件委托(java)
- java设计模式之观察者模式
- java设计模式——观察者模式(Observer Pattern)
- Java设计模式之观察者模式
- java设计模式之观察者模式