观察者模式:当对象间存在一对多关系时,则使用观察者模式(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):实现抽象观察者中定义的抽象方法,以便在得到目标更改通知时更新自身的状态Observer 接口:```javapublic 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;}@Overridepublic 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";@Overridepublic 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) 方法,进行相应的工作。
