观察者模式:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式,又叫发布-订阅模型、模型-视图模式
示例说明:存在一个天气网站,每当天气有更新,都需要通知其他的第三方网站
普通方案设计
- 接受方需要设计一个 update() 方法,用于接受来自数据源的推送
在天气类 WeatherData 中存放需要推送的对象,在 WeatherData 每次存在数据更新时主动调用接收方的 update() 方法进行推送 ```java // 天气数据 public class WeatherData { // 温度 private float temperature; // 气压 private float pressure; // 湿度 private float humidity; // 需要推送的对象 private CurrentConditions currentConditions;
public WeatherData(CurrentConditions currentConditions) {
this.currentConditions = currentConditions;
}
public float getTemperature() {
return temperature;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
// 数据推送 public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
// 数据更新 public void setData(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 数据更新后进行数据推送
this.dataChange();
} }
// 需要推送的对象 public class CurrentConditions { // 温度 private float temperature; // 气压 private float pressure; // 湿度 private float humidity;
// 更新天气情况,由WeatherData进行调用,使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 在更新数据的同时进行输出
display();
}
public void display() {
System.out.println("temperature = " + temperature);
System.out.println("pressure = " + pressure);
System.out.println("humidity = " + humidity);
}
}
缺点:
- 耦合度高,每次新增一个第三方,都需要修改 WeatherData ,在该类中创建一个对应第三方的公告板对象,然后加入到 dataChange() 进行推送,不利于维护
- 无法动态的新增和删除第三方接入
<a name="4xkD9"></a>
#### 观察者模式
- 抽象主题角色(Subject):抽象目标类,提供了一个保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的方法
- 具体主题角色(Concrete Subject):具体目标类,实现了抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象
- 抽象观察者(Observer):抽象类或接口,包含一个更新自己的抽象方法,当接到具体主题的更改通知时被调用
- 具体观察者(Concrete Observer):实现抽象观察者中定义的抽象方法,以便在得到目标更改通知时更新自身的状态
![](https://cdn.nlark.com/yuque/0/2020/gif/750131/1607655919201-4ae1f8f2-c506-45aa-ad75-873c835580fd.gif#align=left&display=inline&height=462&margin=%5Bobject%20Object%5D&originHeight=462&originWidth=590&size=0&status=done&style=none&width=590)
Observer 接口:
```java
public interface Observer {
void update(float temporary,float pressure,float humidity);
}
Subject:
public abstract class Subject {
protected List<Observer> observers;
public Subject() {
this.observers = new ArrayList<>();
}
/**
* 观察者注册
*
* @param observer
*/
void registerObserver(Observer observer){
observers.add(observer);
}
/**
* 移除观察者
*
* @param observer
*/
void removeObserver(Observer observer){
observers.remove(observer);
}
/**
* 通知
*/
abstract void notifyObservers();
}
WeatherData:天气发布类
public class WeatherData extends Subject {
// 温度
private float temperature;
// 气压
private float pressure;
// 湿度
private float humidity;
public float getHumidity() {
return humidity;
}
public float getTemperature() {
return temperature;
}
public float getPressure() {
return pressure;
}
@Override
public void notifyObservers() {
// 向所有的观察者推送数据
observers.forEach(observer -> {
observer.update(getTemperature(),getPressure(),getHumidity());
});
}
// 数据更新
public void setData(float temperature, float pressure, float humidity){
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
// 数据更新后进行数据推送
notifyObservers();
}
}
Consumer:被推送方,消息接收方
public class Consumer implements Observer {
private final static String prefix = "观察者接受到推送:\n";
@Override
public void update(float temporary, float pressure, float humidity) {
System.out.println(prefix + "temporary = " + temporary);
System.out.println("pressure = " + pressure);
System.out.println("humidity = " + humidity);
}
}
java 提供的工具类
在 java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例
Observable 类:抽象目标类,内部有一个 Vector 向量,用于保存所有要通知的观察者对象:
- void addObserver(Observer o) 方法:用于将新的观察者对象添加到向量中
- void notifyObservers(Object arg) 方法:调用向量中的所有观察者对象的 update() 方法,通知它们数据发生改变。通常越晚加入向量的观察者越先得到通知
- void setChange() 方法:用来设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者
Observer 接口:是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。