引言
从我的上篇博客中,我们可以针对气象预报的例子思考两个问题:
(1)观察者种类这么多,每个观察者关心的数据不同,但是被强制通知了一堆数据,这种设计是不是冗余了?
(2)如果哪一天观察者需要拓展功能,需要增加更多的状态,岂不是需要修改和更新每个观察者的调用?
这个问题的解决方案也简单,我们暂且不论,先来看看JAVA内置的观察者模式是怎么实现的。
Java内置的观察者模式
首先我们来看一下JDK的源码。
package java.util;
public class Observable {
private boolean changed = false;//标记被观察者是否改变
private Vector<Observer> obs;//使用线程安全的Vector存储观察者对象
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {//观察者注册
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {//观察者删除
obs.removeElement(o);
}
public void notifyObservers() {//通知观察者
notifyObservers(null);
}
public void notifyObservers(Object arg) {//将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);
}
public synchronized void deleteObservers() {//删除所有观察者
obs.removeAllElements();
}
protected synchronized void setChanged() {//标记被观察者已经改变
changed = true;
}
protected synchronized void clearChanged() {//清除改变
changed = false;
}
public synchronized boolean hasChanged() {//得到改变真假值
return changed;
}
public synchronized int countObservers() {//获取观察者对象
return obs.size();
}
}
public interface Observer {
void update(Observable o, Object arg);
}
根据源码我们考虑,为什么有两个notifyObservers()方法呢,我们观察下这两个的不同点,第一个没有参数,第二个传入了OBJ对象,即一个只是通知观察者我已经发生了改变,至于改变是什么你自己来看(拉模式)。另一个是将整个数据对象全部推送给观察者(推模式)。这样,引言中的疑问我们就解决了。
下面进行上篇博客中天气预报例子的具体实现:
package JAVA内置观察者模式;
import java.util.Observable;
public class WhetherData extends Observable{ //
private float temp;
private float humidity;
private float pressure;
public WhetherData(){
}
public void mesureChanged(){ //气象站气温参数发生变化 调用此接口
setChanged();//通知之前必须声明改变
notifyObservers();
}
public void setMeasurements(float temp,float humidity,float pressure){//可以手动设置气温参数
this.temp=temp;
this.humidity=humidity;
this.pressure=pressure;
mesureChanged();
}
public float getTemp(){
return temp;
}
public float getHumidity(){
return humidity;
}
public float getPressure(){
return pressure;
}
}
package JAVA内置观察者模式;
public interface DisplayElement {
public void display();
}
package JAVA内置观察者模式;
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionDisplay implements Observer, DisplayElement { //具体的观察者
Observable observable;
private float temp;
private float humidity;
public CurrentConditionDisplay(Observable observable){
this.observable=observable;
observable.addObserver(this);
}
public void update(Observable obs,Object org){
if(obs instanceof WhetherData){
WhetherData whetherData=(WhetherData)obs;
this.temp=whetherData.getTemp();
this.humidity=whetherData.getHumidity();
display();
}
}
public void display(){
System.out.print("JAVA内置观察者:现在的温度是:"+humidity+"。现在的湿度是:"+temp);
}
}
package JAVA内置观察者模式;
public class WeatherStation {//入口:气象观测站
public static void main(String args[]){
WhetherData whetherData = new WhetherData();
CurrentConditionDisplay currentConditionDisplay = new CurrentConditionDisplay(whetherData);
whetherData.setMeasurements(12,15,18);
}
}
JAVA内置观察者的问题
因为Observable是一个类,我们必须设计子类继承他,而JAVA没有多继承,如果想要同时拥有Observable类和另一个超类的行为,就会很尴尬。而且setChanged()方法是protect,所以想要使用此方法,必须继承父类,设计违反了第二个设计原则:“多用组合,少用继承”。
小结
观察者模式就讲到这里了,在生活中以及JAVA开发中多思考,你会发现处处都是观察者。
作者:select you from me
链接:https://mp.csdn.net/mdeditor/95638512
来源:CSDN
转载请联系作者获得授权并注明出处。