对象间的联动——观察者模式(十二)

       在使用观察者模式解决实际问题的时候,不同的观察者可能对于同一个目标关注的内容并不相同,对前面的天气实例需求做修改:比如黄明的女朋友只想接收下雨的天气预报,而黄明的母亲想接收下雨或者下雪的天气预报。

       定义目标对象的抽象类,因为要区别对待观察者场景,所以目标对象中的notifyObservers方法不能像前面一样在目标对象中实现,它需要定义成 abstract 的,到具体的目标对象中去实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.wy.observer.example_for_difference;

import java.util.ArrayList;
import java.util.List;

public abstract class WeatherSubject {

//用来保存注册的观察者对象
public List<Observer> observers = new ArrayList<>();

//把订阅天气的人/观察者添加到订阅者列表中
public void attach(Observer observer) {
observers.add(observer);
}

//删除集合中指定的订阅天气的人
public void detach(Observer observer) {
observers.remove(observer);
}

protected abstract void notifyObservers();
}

       定义观察者接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.wy.observer.example_for_difference;

//定义一个更新的接口方法给那些在目标发生改变的时候被通知的观察者对象调用
public interface Observer {

//更新的接口
public void update(WeatherSubject subject);

//设置观察者名称
public void setObserverName(String observerName);

//取得观察者名称
public String getObserverName();
}

       定义具体的目标对象类,天气状态以及订阅者姓名可以设置到常量中,此处从简,通过循环的方式和条件判断来区别通知:

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
package com.wy.observer.example_for_difference;

public class ConcreteWeatherSubject extends WeatherSubject {

//“晴天”“下雨”“下雪”
//目标对象的状态
private String weatherContent;

@Override
protected void notifyObservers() {

//循环所有注册的观察者
for (Observer observer:observers) {

//规则:
//女朋友需要“下雨”的条件通知,其它的条件不通知
//母亲需要“下雨”或者“下雪”的条件通知,其它的条件不通知

//晴天
//do nothing……

//如果下雨
if("下雨".equals(getWeatherContent())){
if("黄明的女朋友".equals(observer.getObserverName())){
observer.update(this);
}
if("黄明的母亲".equals(observer.getObserverName())){
observer.update(this);
}
}

//如果下雪
if("下雪".equals(getWeatherContent())){
if("黄明的母亲".equals(observer.getObserverName())){
observer.update(this);
}
}
}
}

public String getWeatherContent() {
return weatherContent;
}

public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
notifyObservers();
}
}

       观察者接口类的实现:

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
package com.wy.observer.example_for_difference;

public class ConcreteObserver implements Observer {
//观察者的名称
private String observerName;

//天气情况的内容
private String weatherContent;

//提醒的内容
private String remindThing;

@Override
public void update(WeatherSubject subject) {
weatherContent = ((ConcreteWeatherSubject) subject).getWeatherContent();
System.out.println(observerName + "收到了" + weatherContent + "," + remindThing);
}

@Override
public void setObserverName(String observerName) {
this.observerName = observerName;
}

@Override
public String getObserverName() {
return observerName;
}

public String getWeatherContent() {
return weatherContent;
}

public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}

public String getRemindThing() {
return remindThing;
}

public void setRemindThing(String remindThing) {
this.remindThing = remindThing;
}
}

       测试类如下:

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
package com.wy.observer.example_for_difference;

public class Client {

public static void main(String[] args) {
//1 创建目标
ConcreteWeatherSubject weather = new ConcreteWeatherSubject();

//2 创建观察者
ConcreteObserver observerGirl = new ConcreteObserver();
observerGirl.setObserverName("黄明的女朋友");
observerGirl.setRemindThing("下雨了,安静待在家里吧");

ConcreteObserver observerMum = new ConcreteObserver();
observerMum.setObserverName("黄明的母亲");
observerMum.setRemindThing("不管下雨下雪,我都不出门");

//3 注册观察者
weather.attach(observerGirl);
weather.attach(observerMum);

//4目标发布天气
weather.setWeatherContent("下雨");
}
}

       测试效果如下:

1
2
黄明的女朋友收到了下雨,下雨了,安静待在家里吧
黄明的母亲收到了下雨,不管下雨下雪,我都不出门

       将测试类中的天气情况改为下雪:

1
2
3
//4目标发布天气
//weather.setWeatherContent("下雨");
weather.setWeatherContent("下雪");

       测试效果如下,黄明的女朋友不会收到通知,只有黄明的母亲收到了下雪的通知:

1
黄明的母亲收到了下雪,不管下雨下雪,我都不出门

       代码地址详见 PatternTest

参考资料:
GerryZhang 观察者模式 第4章 观察者模式衍生

Fork me on GitHub