观察者模式
业务需求
- 气象站需要测量温度、湿度、气压,发布到平台上
- 需要开放型API,便于第三方可以接入获取气象数据
- API可以提供气象参数的接口,气象站更新数据时可以实时通知第三方
传统方案
-创建天气类,通过get方法让第三方获取信息
- 气象站通过change方法更新数据,第三方法下次获取数据时就会更新,这是第三方主动获取数据
- 第三方也可以被动接收数据;需要推送时,引入第三方的对象,调用他们的update方法进行推送更新
传统方式代码
气象接收方
// 显示天气情况,可以理解为气象站自己的网站
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();
}
// 显示
private void display() {
System.out.println("温度: " + temperature + "******");
System.out.println("气压: " + pressure + "******");
System.out.println("湿度: " + humidity + "******");
}
}
气象站提供信息
// 天气类,提供最新天气消息;引入CurrentConditions对象,用来推送天气消息
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;
dataChange();
}
}
客户端
public class Client {
public static void main(String[] args) {
// 接入方
CurrentConditions currentConditions = new CurrentConditions();
// 天气类
WeatherData weatherData = new WeatherData(currentConditions);
// 更新天气情况
weatherData.setData(30, 0.9f, 13.5f);
// 天气变化
System.out.println("===========更新天气===========");
weatherData.setData(31, 1.1f, 12.3f);
}
}
传统解决方案问题
- 如果增加第三方接收平台,需要增加第三方平台类,修改天气类中多个方法,比较麻烦;不利于维护,不利于动态加入;
- 违反OCP模式;可以使用观察者模式解决
观察者模式解决
观察者接口
// 观察者接口
public interface Observer {
public void update(float temperature, float pressure, float humidity);
}
观察者
public class CurrentConditions implements Observer{
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();
}
// 显示
private void display() {
System.out.println("主站-温度: " + temperature + "******");
System.out.println("主站-气压: " + pressure + "******");
System.out.println("主站-湿度: " + humidity + "******");
}
}
public class BaiduSite implements Observer{
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();
}
// 显示
private void display() {
System.out.println("BaiduSite-温度: " + temperature + "******");
System.out.println("BaiduSite-气压: " + pressure + "******");
System.out.println("BaiduSite-湿度: " + humidity + "******");
}
}
天气类接口
// 天气接口
public interface Subject {
// 注册观察者
public void registerObserver(Observer observer);
// 移除观察者
public void removeObserver(Observer observer);
// 发布信息
public void notifyObserver();
}
天气类,维护数据以及管理观察者
// 天气类,提供最新天气消息;引入观察者集合,用来推送天气消息
public class WeatherData implements Subject{
private float temperature;
private float pressure;
private float humidity;
// 观察者集合
private ArrayList<Observer> observers;
public WeatherData() {
this.observers = new ArrayList<>();
}
public float getTemperature() {
return temperature;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void dataChange() {
notifyObserver();
}
public void setData(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
dataChange();
}
// 维护观察者
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(this.temperature, this.pressure, this.humidity);
System.out.println("===============分割线==============");
}
}
}
客户端
public class Client {
public static void main(String[] args) {
// 创建天气类
WeatherData weatherData = new WeatherData();
// 观察者
CurrentConditions currentConditions = new CurrentConditions();
BaiduSite baiduSite = new BaiduSite();
// 注册到天气类
weatherData.registerObserver(currentConditions);
weatherData.registerObserver(baiduSite);
// 不要的观察者可以移除
// weatherData.removeObserver(baiduSite);
// 发布天气,通知观察者
weatherData.setData(18f, 0.85f, 12.8f);
}
}
JDK源码分析—Observable
java.util.Observable
源码比较较好理解,基本与案例代码结构一致
观察者模式优势
- 通过集合的方式来管理用户,可以对其注册、移除 、通知
- 变动观察者不会影响到维护数据和管理的类