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

       示例:黄明在气象局工作,黄明的女朋友收到天气信息后,准备去和黄明约会;黄明的母亲收到天气信息后,去购物。

       首先我们需要定义观察者接口,代码如下:

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

/**
* 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变的时候被通知的对象
*/

public interface Observer {

/**
* 更新的接口
*
* @param subject 传入目标对象,方便获取相应的目标对象的状态
*/
public void update(WeatherSubject subject);
}

       接下来定义具体观察者,并实现观察者接口:

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

/**
* 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
*/

public class ConcreteObserver implements Observer {
//观察者的名字,是谁收到了这个讯息,黄明的女朋友还是他母亲
private String observerName;

//天气的内容情况,这个消息从目标处获取
private String weatherContent;

//提醒的内容:黄明的女朋友提醒约会,母亲提醒购物
private String remindThing;

/**
* 获取目标类的状态同步到观察者的状态中
*
* @param subject 传入目标对象,方便获取相应的目标对象的状态
*/
@Override
public void update(WeatherSubject subject) {
weatherContent = ((ConcreteWeatherSubject) subject).getWeatherContent();
System.out.println(observerName + "收到了" + weatherContent + "," + remindThing);
}

public String getRemindThing() {
return remindThing;
}

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

public String getObserverName() {
return observerName;
}

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

       然后需要定义目标对象,以天气作为目标对象:

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

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

/**
* 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口
*/

public class WeatherSubject {

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

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

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

//该方法只有子类可以使用,所以定义为受保护的

/**
* 通知所有已经订阅了天气的人
*/
protected void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}

}

       接着就是具体目标对象,继承目标对象:

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

/**
* 具体的目标对象,负责把有关状态存入到相应的观察者对象中
*/
public class ConcreteWeatherSubject extends WeatherSubject {

//获取天气内容信息
private String weatherContent;

public String getWeatherContent() {
return weatherContent;
}

public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//内容有了,说明天气更新了,通知所有的订阅的人
this.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
package com.wy.observer.example;

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("明天天气晴朗,蓝天白云,气温28度");
}
}

       测试效果如下:

1
2
黄明的女朋友收到了明天天气晴朗,蓝天白云,气温28度,是我们的第一次约会,地点街心公园,不见不散哦
黄明的母亲收到了明天天气晴朗,蓝天白云,气温28度,是一个购物的好日子,明天去天虹扫货

       代码地址详见 PatternTest

参考资料:
GerryZhang 改造通用代码解决场景问题

Fork me on GitHub