一.使用java内置的观察者
1.介绍:
在java.util包中包含有基本的Observer接口和Observable抽象类.功能上和Subject接口和Observer接口类似.不过在使用上,就方便多了,因为许多功能比如说注册,删除,通知观察者的那些功能已经内置好了.
2.如何使用:
主题继承Observable抽象类
观察者实现java.util.Observer接口
然后调用Observable对象的addObserver()方法.不想再当观察者时,调用deleteObserver()就可以了
3.被观察者(主题)如何发出通知:
第一步:先调用setChanged()方法,标识状态已经改变的事实.
第二步:调用notifyObservers()方法或者notifyObservers(Object arg),这就牵扯到推(push)和拉(pull)的方式传送数据.如果想用push的方式"推"数据给观察者,可以把数据当做数据对象传送给notifyObservers(Object arg)方法,其中的arg可以为任意对象,意思是你可以将任意对象传送给每一个观察者.如果调用不带参数的notifyObserver()方法,则意味着你要使用pull的方式去主题对象中"拉"来所需要的数据.
4.观察者如何接收通知
观察者只需要实现一个update(Observable o,Object arg)方法,第一个参数o,是指定通知是由哪个主题下达的,第二个参数arg就是上面notifyObserver(Object arg)里传入的数据,如果不传该值,arg为null
二.使用java内置观察者修改气象站案例
1.class WeatherData.java(气象站 主题(继承了java.util.Observable))
package tiglle.pattern.Observer.javaObserver;
import java.util.Observable;
//气象站 主题(继承了java.util.Observable)
public class WeatherData extends Observable{
//天气数据
private int wendu;//温度
private int shidu;//湿度
private int qiya;//气压
//天气数据发生改变时调用,通知观察者
public void weatherChanged(){
//设置父类的changed属性为true,为true时,观察者参会真正更新数据。此方法在更新观察者时拥有更多的弹性
setChanged();
//通知观察者(调用注册进来的观察者的update方法)
notifyObservers();//采用pull拉的方法,观察者自己调用主题的getter方法获取数据
// ;//采用push推的方法,观察者从update方法中的第二个参数args中获取主题传入的数据
}
//设置天气数据,并通知观察者
public void setParam(int wendu,int shidu,int qiya){
this.wendu = wendu;
this.shidu = shidu;
this.qiya = qiya;
//通知观察者
weatherChanged();
}
//设置getter方法,以便观察者自己拉pull数据
public int getWendu() {
return wendu;
}
public int getShidu() {
return shidu;
}
public int getQiya() {
return qiya;
}
}
2.interface Report.java(报导接口,其他功能)
package tiglle.pattern.Observer.javaObserver;
//报导接口
public interface Report {
public void report(int wendu,int shidu,int qiya);
}
3.class HuBeiTv.java(湖北电视台 观察者1(实现java.util.Observer接口))
package tiglle.pattern.Observer.javaObserver;
import java.util.Observable;
import java.util.Observer;
//湖北电视台 观察者1(实现java.util.Observer接口)
public class HuBeiTv implements Observer,Report{
//主题,以便在观察者的构造方法中注册进主题
private Observable observable;
//构造函数,实例化时注册进指定的主题中
public HuBeiTv(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
//使用pull拉的方式让观察者自己用getter从主题获取数据
WeatherData weatherData = (WeatherData) o;
report(weatherData.getWendu(), weatherData.getShidu(), weatherData.getQiya());
}
@Override
public void report(int wendu,int shidu,int qiya) {
System.out.println("湖北人民请注意,当前天气数据,温度:"+wendu+",湿度:"+shidu+",气压:"+qiya);
}
}
4.class HuNanTv.java(湖南电视台 观察者2(实现java.util.Observer接口))
package tiglle.pattern.Observer.javaObserver;
import java.util.Observable;
import java.util.Observer;
//湖南电视台 观察者2(实现java.util.Observer接口)
public class HuNanTv implements Observer,Report{
//主题,以便在观察者的构造方法中注册进主题
private Observable observable;
public HuNanTv(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
//使用pull拉的方式让观察者自己用getter从主题获取数据
WeatherData weatherData = (WeatherData) o;
report(weatherData.getWendu(), weatherData.getShidu(), weatherData.getQiya());
//使用push推的方式获取主题的数据,主题需要调用有参数的notifyObservers(Object o)方法,并传入数据
// int[] param = (int[]) arg;
// report(param[0], param[1], param[2]);
}
@Override
public void report(int wendu, int shidu, int qiya) {
System.out.println("湖南人民请注意,当前天气数据,温度:"+wendu+",湿度:"+shidu+",气压:"+qiya);
}
}
5.MainExec.java(Client(测试main方法))
package tiglle.pattern.Observer.javaObserver;
public class MainExec {
public static void main(String[] args) {
//实例主题
WeatherData weatherData = new WeatherData();
//实例观察者
HuBeiTv huBeiTv = new HuBeiTv(weatherData);
HuNanTv huNanTv = new HuNanTv(weatherData);
//主题数据发生改变
weatherData.setParam(30, 20, 10);
weatherData.setParam(10, 20, 30);
}
}
运行结果:
湖南人民请注意,当前天气数据,温度:30,湿度:20,气压:10
湖北人民请注意,当前天气数据,温度:30,湿度:20,气压:10
湖南人民请注意,当前天气数据,温度:10,湿度:20,气压:30
湖北人民请注意,当前天气数据,温度:10,湿度:20,气压:30
三.缺点
1.观察者Observable是一个类,其子类不能继承其他超类。因为Observable不是一个接口,所以无法换成自定义实现
2.Observable的setChanged()是protected修饰的,只有继承Observable才能使用此方法,所以不能使用组合的方式,违反了“多用组合,少用继承”