天气预报项目需求,具体要求如下:
- 气象站可以将每天测量到的温度、湿度、气压等以公告的形式发布出去(如:发布到自己的网站或第三方)。
- 需要设计开放型API,便于其他第三方也能接入气象站获取数据。
- 提供温度、湿度、气压的接口。
- 测量数据更新时,要能实时的显示或通知给第三方。 普通方案: 通过对气象站项目的分析,我们可以初步设计出一个WeatherData类和WeatherStation类,WeatherData类里面包含了具体的气象数据,当气象数据变更时去更新WeatherStation的公告板。
@Data
public class WeatherData {
private float temperature;
private float humidity;
private float pressure;
private WeatherStation weatherData;
public WeatherData(WeatherStation weatherStation) {
this.weatherData = weatherStation;
}
public void dataChange(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
weatherData.update(this);
}
}
public class WeatherStation {
public void update(WeatherData weatherData) {
display(weatherData);
}
public void display(WeatherData weatherData) {
System.out.println("气象局显示温度" + weatherData.getTemperature());
System.out.println("气象局显示湿度" + weatherData.getHumidity());
System.out.println("气象局显示气压" + weatherData.getPressure());
}
}
public class WeatherTest {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
WeatherData weatherData = new WeatherData(weatherStation);
weatherData.dataChange(20f,20f,1f);
}
}
问题分析: WeatherData类新接入一个第三方时,要加一个成员编码,dataChange方法需要调用第三方的update方法。
- 其他第三方接入气象站获取数据的问题-->扩展性不好。
- 无法在运行时动态的添加第三方。
使用观察者模式来解决
public interface Subject {
void registerObserver(Observer object);
void remove(Observer object);
void notifyObservers();
}
@Data
public class WeatherData implements Subject {
private float temperature;
private float humidity;
private float pressure;
private List<Observer> observers = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
@Override
public void remove(Observer observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
@Override
public void notifyObservers() {
System.out.println("===数据变更,通知观察者");
observers.stream().forEach(o -> o.update(this));
}
public void dataChange(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers();
}
}
public interface Observer {
void update(Object object);
}
public class WeatherStation implements Observer {
@Override
public void update(Object object) {
WeatherData weatherData = (WeatherData) object;
System.out.println("气象局显示温度" + weatherData.getTemperature());
System.out.println("气象局显示湿度" + weatherData.getHumidity());
System.out.println("气象局显示气压" + weatherData.getPressure());
}
}
public class WeatherTest {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
weatherData.registerObserver(new WeatherStation());
weatherData.dataChange(1, 2, 3);
SinaStation sinaStation = new SinaStation();
weatherData.registerObserver(sinaStation);
weatherData.dataChange(2, 3, 4);
weatherData.registerObserver(new BaiduStation());
weatherData.dataChange(3, 4, 5);
weatherData.remove(sinaStation);
weatherData.dataChange(4, 5, 6);
}
}
观察者模式的好处
- 观察者模式设计后,会以集合的方式来管理用户(Observer),register、remove、notify
- 我们增加观察者时,就不需要改核心类WeatherData,遵守了ocp原则。 观察者模式在JDK应用的源码分析
JDK的Observable类就使用了观察者模式
- java.util.Observable
- java.util.Observer
- Observable的作用和地位等价于Subject
- Observable是类,不是接口,类中实现了核心的方法,即管理Observer的方法,add、delete、notify
- Observer观察者,当信息变化时Observable会通知它。