引入
定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖都会收到通知并自动更新。
认识观察者模式
例子:报纸和杂志的订阅
1.报社的业务就是出版报纸
2.向某家报社订阅报纸,只要有新的报纸出版,就会一直为你送报纸
3.当你取消了订阅后,将不会为你送新报纸
4.只要报社在运营,就会一直有人或单位订阅报纸或取消订阅。
出版社+订阅者=观察者 模式
UML类图
以上包含subject与observer接口的类设计最为常见
1.subject主题接口,对象使用此接口注册为观察者或者把自己从观察者中删除
2.observer所有的观察者必须实现此接口,这个接口只有一个update方法。当主题状态改变时它被调用
3.ConcreteSubject一个具体主题实现了主题接口,除了注册和撤销方法,还实现了notifyObserver方法,此方法在主题 状态改变时更新所有当前观察者
4.具体的观察者可以是实现Observer接口的任意类,观察者必须注册主题,以便接受更新
示例
这里引用head first上一个例子
package com.zpkj.project4;
/**
* subject接口
*/
public interface SubjectInter {
void registerObserver(ObserverInter observerInter);
void removeObserver(ObserverInter observerInter);
void notifyObserver();
}
package com.zpkj.project4;
/**
* Observer接口
*/
public interface ObserverInter {
void update(float temp,float humidity,float pressure);
}
package com.zpkj.project4;
import java.util.ArrayList;
/**
* ConcreteSubject 实现类
*/
public class WeatherData implements SubjectInter{
private ArrayList<ObserverInter> observerInters;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
super();
observerInters =new ArrayList<ObserverInter>();
}
@Override
public void registerObserver(ObserverInter observerInter) {
observerInters.add(observerInter);
}
@Override
public void removeObserver(ObserverInter observerInter) {
int num = observerInters.indexOf(observerInter);
if(num>=0){
observerInters.remove(num);
}
}
@Override
public void notifyObserver() {
for(int i = 0;i < observerInters.size();i++){
ObserverInter observerInter = observerInters.get(i);
observerInter.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObserver();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
package com.zpkj.project4;
/**
* ConcreteObserver 实现类
*/
public class CurrentConditionsDisplay implements ObserverInter,DisplayElementInter{
private SubjectInter weatherData;
private float temperature;
private float humidity;
private float pressure;
public CurrentConditionsDisplay(SubjectInter subjectInter){
super();
this.weatherData = subjectInter;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("气温:"+temperature+" 湿度:"+humidity+" 压力:"+pressure);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
/**
* 负责显示天气信息接口
*/
package com.zpkj.project4;
public interface DisplayElementInter {
void display();
}
总结
有几点需要注意的是
- Subject 和 Observer 是一个一对多的关系,也就是说观察者只要实现 Observer 接口并把自己注册到 Subject 中就能够接收到消息事件;
- Java API有内置的观察者模式类:java.util.Observable 类和 java.util.Observer 接口,这分别对应着 Subject 和 Observer 的角色;
- 使用 Java API 的观察者模式类,需要注意的是被观察者在调用 notifyObservers() 函数通知观察者之前一定要调用 setChanged() 函数,要不然观察者无法接到通知;
- 使用 Java API 的缺点也很明显,由于 Observable 是一个类,java 只允许单继承的缺点就导致你如果同时想要获取另一个父类的属性时,你只能选择适配器模式或者是内部类的方式,而且由于 setChanged() 函数为 protected 属性,所以你除非继承 Observable 类,否则你根本无法使用该类的属性,这也违背了设计模式的原则:多用组合,少用继承。
引用
[1] 弗里曼. Head First 设计模式(中文版)[Z]. 中国电力出版社: O'Reilly Taiwan公司 ,2007.
https://blog.youkuaiyun.com/self_study/article/details/51346849