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

设计模式随笔-观察者模式

2016-09-04 18:57 399 查看

观察者模式

观察者模式是JDK中使用最多的模式之一,非常有用。它是一对多关系,以及松耦合。有了观察者,你将会消息灵通。

天气监测应用概况

现在有一个应用:气象监测系统。

此系统中有三个部分分别是:气象站(获得实际气象数据的装置)、WeatherData对象(追踪来自气象站的数据,并更新数据)和显示器(显示目前天气状况给用户看)。

如下图所示:



需求

现在我们接受这个项目,我们的工作就是建立一个应用,利用WeatherData对象获取气象站的实时数据,并更新到显示器上面:目前状况显示器、气象统计显示器和天气预报显示器。

新鲜出炉的WeatherData类

如图:



measurementsChanged()方法能调用三个天气显示器实时更新数据。方法如下:

public void measurementsChanged(){
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();

//分别调用三个显示器对象的update()方法更新天气显示器信息
currentConditionsDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}


但是上面针对的实现编程,会导致我们以后再正价或者删除布告板是必须修改代码。改变的地方需要封装起来、针对接口编程而不针对实现编程。

认识观察者模式

就像报纸的订阅,出版商+订阅者=观察者模式。

出版者=“主题”,订阅者=“观察者”

详细分析如下图:



观察者模式定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

观察者模式UML图如下:



观察者模式样例代码

首先是主题(Subject)接口代码:

/**
* 观察者模式里面的-主题
* Created by zz on 2016/8/24.
*/
public interface Subject {
/**
* 注册订阅者
* @param observer
*/
public void registerObserver(Observer observer);

/**
* 取消订阅者
* @param observer
*/
public void removeObserver(Observer observer);

/**
* 当主题状态改变时,通知所有订阅者
*/
public void notifyObject();
}


订阅者(Observer)接口代码:

/**
* 订阅者
* Created by zz on 2016/8/24.
*/
public interface Observer {
public void update(float temp, float humidity, float pressure);
}


WeatherData类代码实现:

public class WeatherData implements Subject {
private List<Observer> observers;    //订阅者
private float temperature;    //温度
private float humidity;    //湿度
private float pressure;    //压强

public WeatherData(){
observers = new ArrayList<Observer>();
}

@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
int i = observers.indexOf(observer);
if (i > 0){
observers.remove(i);
}
}

@Override
public void notifyObject() {
for (int i=0; i<observers.size(); i++){
Observer observer = observers.get(i);
observer.update(temperature, humidity, pressure);
}
}

/**
* 当主题改变时调用的方法
*/
public void measurementsChange(){
notifyObject();
}

public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChange();
}
}


显示器(CurrentConditionsDisplay)类代码实现:

public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;    //温度
private float humidity;    //湿度
private Subject weatherData;

public CurrentConditionsDisplay(Subject subject){
this.weatherData = subject;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println(temperature + ":" + humidity);
}

@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
//改变的方法提取出来
public interface DisplayElement {
public void display();
}


test方法测试:

public void test(){
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);    //订阅主题
weatherData.setMeasurements(80, 65, 30.4F);
weatherData.setMeasurements(75, 70, 29.2F);
weatherData.setMeasurements(78, 90, 29.2F);
}


上面的代码我只写了一个显示天气温度的显示器类,还有其他湿度显示器等也是同样原理,只是可能计算湿度的算法不一样而已,这里就不在累赘讲述了。

JAVA内置的观察者模式

在java.util包中内含了一个叫Observer接口与Observable类,这与我们自己手动创建的Subject接口与Observer接口很相似。只是java内置的Observable是一个抽象类,而我们都用了接口来实现。

下面是利用java内置的气象站OO设计:



内置的java观察者模式是如何把对象变成观察者的呢?其实和自己设计的观察者模式一样,该内置的java方法调用了Observable对象的addObserver()方法。如果不想在当观察者的话就调用该对象的removeObserver()方法。

那观察者如何收到通知呢?通过先调用Observaable对象的setChanged()方法,然后调用notifyObservers()方法通知就可以调用所有在该对象注册的观察者对象了。为什么要先调用setChanged(),这是因为内置的java观察者有一个标志位boolean change,当把标志位修改成ture时,notify方法才会执行通知。

那接收者是如何接收到通知的呢?主要是通过Observer接口的update()方法了,同自己设计的一个样:

public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param   o     the observable object.
* @param   arg   an argument passed to the <code>notifyObservers</code>
*                 method.
*/
void update(Observable o, Object arg);
}


Object arg参数没有说明时可以传空。

利用内置的java观察者模式重做气象站

WeatherData代码:

import java.util.Observable;

/**
* 内置java观察者
* Created by zz on 2016/8/24.
*/
public class WeatherData extends Observable {
private float temperature;    //温度
private float humidity;    //湿度
private float pressure;    //压强
public WeatherData(){}

public void measurementsChanged(){
setChanged();
notifyObservers();
}

public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}

public float getTemperature() {
return temperature;
}

public float getHumidity() {
return humidity;
}

public float getPressure() {
return pressure;
}
}


某个显示器:

import java.util.Observable;
import java.util.Observer;

/**
* Created by zz on 2016/8/25.
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable){
this.observable = observable;
observable.addObserver(this);
}

@Override
public void display() {
System.out.println("temperature:"+temperature + "humidity:"+ humidity);
}

@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData){
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
}


大家可能注意到了Observable是一个类,而不是一个接口,而且它也没有实现一个接口,这样可能限制了它的使用和复用。这一点需要大家注意一下哦。

在jdk中还有挺多地方用到观察者模式的哦,比如:Swing和javaBeans中,他们都实现了观察者模式,有时间大家可以看看哟。

总结

在本章中,让我学到了一些知识:

1.为交互对象之间的松耦合设计而努力。

2.观察者模式-在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jdk 设计模式