观察者模式
0 定义
观察者模式定义对象之间的一对多的依赖,这样依赖,当一个对象改变状态时,他的所有依赖都会收到通知并自动更新。
1 简述
观察者模式可以想象一个场景,就是以前订阅报纸的情况,首先需要去出版社去注册自己的信息,出版社根据注册信息表来配送报纸的地址,观察者模式的大致情况也是这样的,只不过名词换一下,出版社换成主题,订阅者换成观察者,观察者模式一般有两种实现方式,拉和推;如图一所示,观察者模式的UML图,
2 实例
本身
JAVA有实现观察者模式,我们这里就用JAVA里的来介绍实例,建议阅读一下java.util.Observable、java.util.Observer,Observable是一个主题,Observer是观察者。 我们先提一个需求,现在有一个天气公司可以获取各自数据如温度、湿度、风向等,我们需要根据其数据来实现不同类型的公告版,并且当数据更新的时候,需要通知公告板去获取数据。例如有一个公告板实现温度预测,有一个实现当前温度说明等等,展现出不同的形式。首先我们先忘记观察者模式,想象有其他我们学习的可以实现吗?比如策略模式,使用策略模式确实可以封装变化,当我们使用公告板的时候就可以加上其实现类就行,但是他无法做到通知公告板去更新数据。所以是不可以的,别问我其他的模式,我还没有学会。
主题实现
import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
}
public void measurementsChanged(){
setChanged();
notifyObservers();
}
//通过这个方法自定义触发天气站的数据更新
private 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;
public class CurrentConditionsDisplay implements Observer {
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
//观察者都要实现的方法
@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();
}
}
public void display(){
System.out.println("current condition : "+temperature+"F degrees and"+ humidity+"% humidity");
}
}
看以上代码,我们思考几个问题:
- 如何让对象变成观察者
- 主题如何发出通知,采用什么方式拉还是推
- 观察者如何接收到通知 答案:
- 我们看观察者的构造方法
public CurrentConditionsDisplay(Observable observable),观察者首先要获取到主题对象,在自己决定进行的操作,这里我们调用addObserver方法来把观察者加入到主题的中。 - 首先main方法中调用
setMeasurements,自定义模拟天气站的数据更新,在调用measurementsChanged方法来通知注册的观察者。 - 这里涉及到
Observable两个方法,我们知道观察者有两种方式,一种是拉,一种是推,对应着其中两个方法。,第一个是notifyObservers(Object arg),采用的是推的方式。第二个采用的是拉的方式
notifyObservers()所以我们应该看出其中的相同点啦,就是主题通知方法是否带数据,上面我们的示例代码就是采用拉的方式,可以参考一下。
3 设计原则
- 面向接口编程
- 多用组合,少用继承
- 封装变化
- 为交互对象之间的松耦合设计而努力
4 要点
- 观察者定义了对象之间一对多的关系
- 主题(可观察者)用一个共同的接口来更新观察者。
- 观察者和主题之间用松耦合方式结合,主题不知道观察者的细节,只知道观察者实现了观察者的接口。
- 使用此模式,你可以从被观察者处推或者拉数据(然而,推这个方式被认为更正确)
- 有多个观察者时,不可以依赖特定的通知顺序。
- java实现多种观察者模式的实现。包括通用的
java.util.Observable. - 要注意
java.util.Observable实现上带来的问题,(面向实现的问题) - 如果有必要的话自己实现
Observable
5 扩展
- java观察者模式不好的地方-面向实现编程的坏处。
- 观察者模式中设置setChange的好处-增加程序的弹性