观察者与多主题

一个观察者可以依赖于多个具体主题,当所依赖的任何具体主题的数据发生变化时,该观察者都能得到通知。多主题所涉及的问题是观察者如何处理主题中变化后的数据,因为,不同的具体主题所含有数据的机构可能有很大的不同。

在处理多主题时,观察者接口可以将更新数据方法的参数类型设置为主题接口类型,比如update(Subject subject),即具体主题数据发生变化时将自己的引用传递给具体的观察者,然后具体的观察者让这个具体的主题调用有关的方法返回该具体主题中的数据。

以下通过简单的问题说明多主题的设计。

李先生希望及时知道气象站所维护的每日的天气数据,比如最高气温和最低气温等,同时希望及时知道旅行社每日的旅游信息。

按着观察者的模式,李先生就是一个具体的观察者,而气象站和旅行社是他依赖的两个具体主题,根据观察者模式的结构,给出的设计如下。

1.主题

1
2
3
4
5
public interface Subject {
public void addObserver(Observer o);
public void deleteObserver(Observer o);
public void notifyObservers();
}

2.观察者

1
2
3
public interface Observer {
public void update(Subject subject);
}

3.具体主题

在本问题中,气象站和旅行社是两个具体主题。

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// WeatherStation.java
public class WeatherStation implements Subject {
String forecastTime, forecastMess;
int maxTemperature, minTemperature;
ArrayList<Observer> personList;
public WeatherStation() {
personList = new ArrayList<Observer>();
}
@Override
public void addObserver(Observer o) {
if (o == null) {
return;
}
if (! personList.contains(o) ) {
personList.add(o);
}
}
@Override
public void deleteObserver(Observer o) {
if (personList.contains(o)) {
personList.remove(o);
}
}
@Override
public void notifyObservers() {
for (int i = 0; i < personList.size(); i++) {
personList.get(i).update(this);
}
}
public void doForecast(String t, String mess, int max, int min) {
forecastTime = t;
forecastMess = mess;
maxTemperature = max;
minTemperature = min;
notifyObservers();
}
public String getForecastTime() {
return forecastTime;
}
public String getForecastMess() {
return forecastMess;
}
public int getMaxTemperature() {
return maxTemperature;
}
public int getMinTemperature() {
return minTemperature;
}
}

// TraverAgency.java
public class TraverAgency implements Subject {
String tourStartTime;
String tourMess;
ArrayList<Observer> personList;
public TraverAgency() {
personList = new ArrayList<Observer>();
}
@Override
public void addObserver(Observer o) {
if (o == null) {
return;
}
if (! personList.contains(o)) {
personList.add(o);
}
}
@Override
public void deleteObserver(Observer o) {
if (personList.contains(o)) {
personList.remove(o);
}
}
@Override
public void notifyObservers() {
for (int i = 0; i < personList.size(); i++) {
personList.get(i).update(this);
}
}
public void giveMess(String time, String mess) {
tourStartTime = time;
tourMess = mess;
notifyObservers();
}
public String getTourStartTime() {
return tourStartTime;
}
public String getTourMess() {
return tourMess;
}
}

4.具体观察者

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
public class Person implements Observer {
Subject subjectOne, subjectTwo;
String forecastTime, forecastMess;
String tourStartTime, tourMess;
int maxTemperature, minTemperature;
public Person(Subject subjectOne, Subject subjectTwo) {
this.subjectOne = subjectOne;
this.subjectTwo = subjectTwo;
subjectOne.addObserver(this);
subjectTwo.addObserver(this);
}
@Override
public void update(Subject subject) {
if (subject instanceof WeatherStation) {
WeatherStation ws = (WeatherStation) subject;
forecastTime = ws.getForecastTime();
forecastMess = ws.getForecastMess();
maxTemperature = ws.getMaxTemperature();
minTemperature = ws.getMinTemperature();
System.out.print("预报日期:"+ forecastTime +",");
System.out.print("天气情况:"+ forecastMess +",");
System.out.print("最高温度:"+ maxTemperature +",");
System.out.println("最低温度:"+ minTemperature +",");
} else if (subject instanceof TraverAgency) {
TraverAgency ta = (TraverAgency) subject;
tourStartTime = ta.getTourStartTime();
tourMess = ta.getTourMess();
System.out.print("旅游开始日期:"+ tourStartTime +",");
System.out.println("旅游信息:"+tourMess+"。");
}
}
}

5.测试程序

1
2
3
4
5
6
7
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
TraverAgency traverAgency = new TraverAgency();
Person meng = new Person(weatherStation, traverAgency);
weatherStation.doForecast("10 日", "阴有小雨", 28, 20);
traverAgency.giveMess("10 日", "黄山两日游");
}

欢迎关注我的其它发布渠道