head first 设计模式读书笔记-观察者模式
观察者模式
需求
有一个气象站,会随时更新气象信息。同时,有各种显示器,会展示这些气象信息。现在需要气象站每次更新数据时可以将新的数据及时推送到显示屏。
代码实现
我们现在有一个 WeatherData
(气象站)对象,负责产生新的天气数据,还有一个 CurrentConditionsDisplay
(显示屏)对象,用来显示最新的气象数据,这个对象也就是观察者。观察者在气象站注册 (registerObserver
) 之后,气象站如果有最新的数据就会及时提醒 ( notifyObservers
) 已经注册的观察者,及时更新显示。如果这个显示屏不想再接收到这个最新的气象数据,气象站可以将这个显示屏从气象站的通知列表中删除 ( removeObserver
) ,下次气象站有数据更新时,将不会通知这个显示屏。
- 定义一个借口,规定气象站应该有的功能
1 | /** |
- 实现一个气象站
1 | /** |
定义两个接口,规定一个显示屏应该有的功能
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 规定观察者应该有更新自身数据的功能
*/
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
/**
* 规定观察者应该有显示的功能
*/
public interface DisplayElement {
void display();
}定义两个显示屏,分别显示现在的天气状况和明天的天气状况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71/**
* 实时气温显示屏
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
WeatherData weatherData;
/**
* 每次生成一个显示屏,就向气象站注册
*
* @param weatherData
*/
public CurrentConditionsDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void display() {
System.out.println("现在的天气是: " + temperature + " ℃,相对湿度是:
" + humidity + "%,大气压是:" + pressure + "kPa");
}
/**
* 更新显示屏显示的数据
*
* @param temperature
* @param humidity
* @param pressure
*/
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
/**
* 天气预报显示屏
*/
public class ForecastDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
WeatherData weatherData;
public ForecastDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void display() {
System.out.println("现在的天气是: " + temperature +
" ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}代码测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class WeatherStationTest {
public void runWeatherStation() {
// 定义一个气象站
WeatherData weatherData = new WeatherData();
// 生成一个 实时温度 显示屏
CurrentConditionsDisplay currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);
// 生成一个 天气预报显示屏
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
// 气象站更新数据两个显示屏都会显示
weatherData.setMeasurements(25, 60, 101.3f);
System.out.println("我现在只想看天气预报-----------");
// 现在将实时气温显示屏移除,以后气象站更新数据,只会通知天气预报显示屏
weatherData.removeObserver(currentConditionsDisplay);
weatherData.setMeasurements(26, 55, 101.4f);
}
}运行效果
1
2
3
4现在的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.3kPa
明天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.3kPa
我现在只想看天气预报-----------
明天的天气是: 26.0 ℃,相对湿度是: 55.0%,大气压是:101.4kPa
使用jdk自带的类来实现上述功能
在 java.util
包中有两个类 Observable
和 Observer
,可以帮助我们实现上面的功能
定义气象站的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
}
/**
* 调用提醒方法
*/
public void measurementsChanged() {
/* 设置 Observable 类中的 changed 属性为 true,只有当 changed 属性为 true 时,
* notifyObservers 方法内部才会调用各个显示屏的update的方法
*/
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}定义两个显示屏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75/**
* 当前气温显示屏
* DisplayElement 代码同上
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;
private float pressure;
// 构建一个显示屏时,向气象站注册
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void display() {
System.out.println("今天的天气是: " + temperature +
" ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
}
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
this.pressure = weatherData.getPressure();
display();
}
}
}
import java.util.Observable;
import java.util.Observer;
/**
* 天气预报显示屏
*/
public class ForecastDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
Observable observable;
public void display() {
System.out.println("明天的天气是: " + temperature +
" ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
}
public ForecastDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
humidity = weatherData.getHumidity();
temperature = weatherData.getTemperature();
pressure = weatherData.getPressure();
display();
}
}
}
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class WeatherStation {
public void runWeatherStation2() {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(25, 60, 101.1f);
System.out.println("------现在我们把当前温度移除--------");
weatherData.deleteObserver(currentConditionsDisplay);
weatherData.setMeasurements(32, 71, 101.6f);
}
}运行结果
1
2
3
4明天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.1kPa
今天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.1kPa
------现在我们把当前温度移除--------
明天的天气是: 32.0 ℃,相对湿度是: 71.0%,大气压是:101.6kPa
head first 设计模式读书笔记-观察者模式
You need to set
install_url
to use ShareThis. Please set it in _config.yml
.