您的位置:首页 > 编程语言 > Java开发

JAVA设计模式之观察者模式

2018-02-05 10:58 399 查看
观察者模式是日常开发中最为常用的设计模式之一,本文主要分为四个部分:1、什么是观察者模式 2、观察者模式由哪些组件构成 3、使用观察者模式实现天气预报布告栏的案例 4、使用JDK内置的观察者模式实现天气预报布告栏的案例。

什么是观察者模式

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象的状态发生改变时,它的所有依赖者都会收到通知,并且做出改变。

在现实生活中,可以找到很多跟观察者模式有关的例子,比如说猎头和求职者之间就是一种一对多的关系,有一个猎头,求职者们可以在他那儿登陆注册,留存简历,当猎头发现有合适的工作时会将应聘信息发送给这些人,求职者可以随时跟猎头建立或者取消合作关系,一旦取消合作关系,猎头就不会再发送应聘信息给对应的求职者,这其中猎头就扮演一种有状态的对象,而求职者就是依赖猎头的对象,他们是一对多的关系。



观察者模式由哪些组件构成

根据观察者模式的概念,我们很容易想到,观察者模式中的两种核心组件,即主题对象(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,"下雪");
}
}


运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: