顾名思义就是观察者从被观察者身上拉取自己需要的数据!
类结构图同拉的方式,不过具体代码上会有点区别!
本案中被观察者接口和观察者接口我们采用的是JDK自带的API来写!里面已经考虑了多并发的情况。但是他的观察者是一个类,又因为java是单继承的,所以在这点稍微有点不好!但是想把一些基础的功能搞定的话,必须使用类来操作。矛盾啊!
被观察者的实现
package com.alibaba.test.observer.api;
import java.util.Observable;
public class WeatherData2 extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void setMeaturements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
changed();
}
public void changed() {
setChanged(); //这步很有必要,这样我们就可以有更多的弹性,可以适当的通知观察者,比如说在10秒通知一次,那么就不需要每次实时很敏感的通知!
// if time & 10 == 0 {....}
notifyObservers();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
//测试代码,这里可以清晰的看到,没有建立观察者和被观察者之间的关系,两者之间关系的确立时在观察者内!具体看观察者的代码!
public static void main(String[] args) {
WeatherData2 data2 = new WeatherData2();
new BObserver(data2);
data2.setMeaturements(0.6f, 0.9f, 2.0f);
}
}
观察者的实现:
package com.alibaba.test.observer.api;
import java.util.Observable;
import java.util.Observer;
import com.alibaba.test.observer.DisplayMent;
public class BObserver implements Observer, DisplayMent {
private float t;
private float h;
private Observable o;
//这里将自己加入了观察者的队列中!
public BObserver(Observable o) {
this.o = o;
this.o.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
//对于被观察者对象的数据封装起来,观察者自己主动获取需要的数据,如果做的更好的话,可以再建立一个上下文来封装数据
if (o instanceof WeatherData2) {
//这点也非常重要,我们可以利用JDK的观察者模式添加多个观察者,然后通过判断的方式来获取自己需要的数据,但是又会有一个问题,被观察对象是继承了Observer,那么在有多个不同类型或者是纬度的被观察者时,会造成一定的性能问题。故在某些情况下有必要做下区分!或者自己重写JDK的Observer
WeatherData2 temp = (WeatherData2) o;
this.t = temp.getTemperature();
this.h = temp.getHumidity();
display();
}
}
@Override
public void display() {
System.out.println("the temperature is:" + t + " the humidity is :" + h);
}
}
问题;
JDK的 Observer内部实现是vector + syncd的方式,防止多并发,有必要改写下!
可以看下他的通知所有观察者的实现:
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal; //这里采用的是对象拷贝的方式
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
采用JDK版本的缺陷:
1. 主题也就是被观察者是一个类,在JAVA中是单继承的方式,如果继承了这个类,就无法继承其他的方式
2. 也因为是类,并且setChanged()是priotected 那么就必须采用继承的方式,违法的多用组合,少用继承的原则!
好的做法是重写这个observer,因为这个类出现的比较早,在考虑多线程方面,采用的都是早期的类,可以换用JDK5后的并发包!
要点总结:
1.被观察者对象持有观察者的对象集合
2.被观察者拥有添加,删除,通知所有观察者对象的行为
3.方式有推和拉两种,两者的本质区别是一种把添加观察对象的操作在被观察者这边,另一种是在观察者对象将自己添加到被观察者对象集合中,本质上是一样的
4.有多个观察者时,不需要依赖特定的顺序
使用场景:
图形界面编程的 SWING AWT GWT等,触发监听器!