把对象变成观察者:实现观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法或deleteObserver()
可观察者送出通知:
1、扩展java.util.Observable类产生"可观察者"类
2 、1)先调用Observable的setChanged()方法,标记主题的状态已经改变,让notifyObservers()知道当它被调用时应该更新观察者,如果调用notifyObservers()之前没有调用setChanged(),观察者就不会被通知更新。
Observable的setChanged()方法(修饰符是protected,不能创建Observable实例并组合到自己的对象中因为不能使用setChanged()方法,除非继承Observable类):
protected synchronized void setChanged() {
changed = true;
}
2)调用两种notifyobservers()方法中的一个:
notifyobservers()或notifyobservers(Object arg)
java.util.Observable的notifyobservers(Object arg)的方法:
Object arg:当通知时,可以把arg(数据对象data object)通过update方法传送给每一个观察者
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
java.util.Observable的notifyobservers()方法:
public void notifyObservers() {
notifyObservers(null);
}
观察者如何接收通知:
观察者实现了跟新的方法:
update(Observable o,Object arg)
Observable o:主题本身当作第一个变量,好让观察者知道是哪个主题通知它的
Object arg:是传入notifyobservers()的数据对象,如果没有则说明为空。
如果想"推"(push)数据给观察者,可以把数据当作数据对象传送给notifyobservers()方法。否则,观察者必须从可观察者对象中"拉"(pull)数据。
下面通过观察者从可观察者处拉数据的演示:
1、把WeatherData改成使用java.util.Observable
package com.ya;
import java.util.ArrayList;
import java.util.Observable;
public class WeatherData extends Observable{
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){ }
public void measurementsChanged(){
//调用notifyObservers()方法之前先调用setChanged()
setChanged();
//如果该方法的参数没有Object数据对象,这表示采用的是观察者主动向可观察者"拉"的方式
notifyObservers();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
//下面三个方法,因为我们要使用"拉"的做法,观察者会利用这些方法获得WeatherData对象的状态
public float getTemperature(){
return temperature;
}
public float getHumidity(){
return humidity;
}
public float getPressure(){
return pressure;
}
}
CurrentConditionsDisplay布告板:
package com.ya;
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer,DisplayElement{
Observable observable;
private float temperature;
private float humidity;
private float pressure;
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable obs, Object obj) {
if(obs instanceof WeatherData){
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
display();
}
public void display(){
System.out.println("Current conditions:" + temperature + "F degrees and"+ humidity +" %humidity");
}
}
测试代码类WeatherStation:
package com.ya;
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
}
}
有多个公布板时(观察者),测试结果每次输出的次序不一样,而自定义观察者的模式输出次序每次输出都一样。
这是因为java.util.Observable实现了notifyObservers()方法,调用观察者的update的次序与自定义的观察者模式不一样。
//java内置的可观察者调用观察者的update的次序是后加入的先调用
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
//自定义的观察者模式调用观察者的update的次序是先加入的先调用
for(int i=0;i<observers.size();i++){
Observer observer = (Observer)observers.get(i);
observer.update(temperature,humidity,pressure);
}
在JDK中,不是只有java.util中才能找到观察者模式,在JavaBeans和Swing中,也都实现了观察者模式。