1. 模式引出–天气预报项目需求
天气预报项目需求,具体要求如下:
-
气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。
-
需要设计开放型API,便于其他第三方也能接入气象站获取数据。
-
提供温度、气压和湿度的接口
-
测量数据更新时,要能实时的通知给第三方
1.1 天气预报普通设计方案
通过对气象站项目的分析,我们可以初步设计出一个WeatherData类
说明:
-
通过getXxx方法,可以让第三方接入,并得到相关信息.
-
当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送。
1.2 代码实现
WeatherData.java
/**
* 类是核心
* 1.包含最新的天气情况信息
* 2.含有CurrentConditions对象
* 3.当数据有更新时,就主动的调用CurrentConditions对象 update方法(含display),这样他们(接入方)就看到最新的信息
*
* @author ACER1
*
*/
public class WeatherData {
private float temperatrue;
private float pressure;
private float humidity;
private CurrentConditions currentConditions;
public WeatherData(CurrentConditions currentConditions) {
this.currentConditions = currentConditions;
}
public float getTemperature() {
return temperatrue;
}
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.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
//调用dataChange,将最新的信息推送给接入方
dataChange();
}
}
CurrentConditions.java
/**
* 显示当前天气情况(可以理解成是气象站自己的网站)
*
* @author ACER1
*
*/
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("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
测试Main.java
public class Main {
public static void main(String[] args) {
// 创建接入方currentConditions
CurrentConditions currentConditions = new CurrentConditions();
// 创建WeatherData并将接入方currentConditions传递到WeatherData中
WeatherData weatherData = new WeatherData(currentConditions);
// 更新天气情况
weatherData.setData(30, 150, 40);
}
}
输出结果
问题分析
-
其他第三方接入气象站获取数据的问题
-
无法在运行时动态的添加第三方 (新浪网站)
-
违反ocp原则=>观察者模式
2. 观察者模式原理
对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化.
Subject:登记注册、移除和通知
Observer:接收输入
3. 观察者模式解决天气预报需求
UML类图
Observer.java
// 观察者接口
public interface Observer {
public void update(float temperature,float pressure,float humidity);
}
Subject.java
// 主题接口
public interface Subject {
// 注册
public void registerObserver(Observer o);
// 移除
public void removeObserver(Observer o);
// 通知
public void notigyObserver();
}
CurrentConditions.java
// 具体观察者
public class CurrentConditions implements Observer {
private float temperature;
private float pressure;
private float humidity;
private String name;
public CurrentConditions(String name) {
this.name = name;
}
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(name + ": Today mTemperature: " + temperature );
System.out.println(name + ": Today mPressure: " + pressure);
System.out.println(name + ": Today mHumidity: " + humidity);
}
}
WeatherData.java
// 被观察的主题
public class WeatherData implements Subject {
private float temperatrue;
private float pressure;
private float humidity;
private List<Observer> observers;
public WeatherData(List<Observer> observers) {
this.observers = observers;
}
public float getTemperature() {
return temperatrue;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
notigyObserver();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notigyObserver() {
for (Observer o : observers) {
o.update(temperatrue, pressure, humidity);
}
}
}
测试Main.java
public class Main {
public static void main(String[] args) {
Observer a = new CurrentConditions("a");
Observer b = new CurrentConditions("b");
List<Observer> list = new ArrayList<>();
list.add(a);
list.add(b);
WeatherData weatherData = new WeatherData(list);
weatherData.setData(1, 1, 1);
weatherData.removeObserver(b);
System.out.println();
weatherData.setData(2, 2, 2);
}
}
输出结果
4. 观察者模式的好处
-
观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
-
这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherData不会修改代码,遵守了ocp原则。
5. 观察者模式在Jdk1.8的应用
在jdk1.8中,有一个Observable
类:
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
...
}
可以看到其中有一个obs的属性成员,范型类型为Observer
,并在类初始化时完成空间申请。
开始追Observer
代码
public interface Observer {
void update(Observable o, Object arg);
}
可以看到,Observer
是一个接口,其中只有一个方法,update
,和上例定义的的观察者接口时一样的功能。
回来看Observable
类,Observable
类并没有实现那个主题接口,而是直接充当了具体主题,可以看到Observable类中实现的方法列表
在其中可以看到主要的方法
addObserver(Observer)
deleteObserver(Observer)
notifyObservers()
使用java1.8提供的Observable
类可以直接实现观察者模式,不需要重新构建
小结
- Observable 的作用和地位等价于前面的Subject
- Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理Observer的方法 add… delete … notify…
- Observer 的作用和地位等价于前面的 Observer, 有update
- Observable 和 Observer 的使用方法和前面的一样,只是Observable 是类,通过继承来实现观察者模式
转载:https://blog.csdn.net/qq_40963076/article/details/106259506