设计模式(五)观察者模式

观察者模式(Observer)是 JDK 中使用最多的模式之一

有时候,我们的对象需要在收到某些通知时及时作出响应,此时可以用观察者模式。观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

图片来自《Head First 设计模式》

可以以订阅报纸类比,出版社作为发布者,所有订阅了报纸的用户,在有新报纸出版时,都会收到一份最新的报纸。只不过,在观察者模式中,出版社叫做 主题(Subject),订阅者叫 观察者(Observer)


主题(Subject)

主题就是发送通知的人。

1
2
3
4
5
public interface Subject {
void registerObserver(Observer observer); // 注册一个观察者
void removeObserver(Observer observer); // 取消注册
void notifyObservers(); // 发送通知
}

一个可以发布小说和新闻的报社,它维护了一个观察者列表,需要订阅这家报社的人,都会被加到这个 List 进来。

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 Publisher implements Subject {
private List<Observer> observers;
private String story; // 小说
private String news; // 新闻

Publisher(){
observers = new ArrayList<>(6);
}

@Override
public void registerObserver(Observer o) {
observers.add(o);
}

@Override
public void removeObserver(Observer o) {
observers.remove(o);
}

// 对每一个观察者都进行通知
@Override
public void notifyObservers() {
observers.forEach(o -> o.update(story, news));
}

// 设置通知信息
public void setMessages(String story, String news){
this.story = story;
this.news = news;
notifyObservers();
}
}

观察者(Observer)

观察者就是接收通知的人,当有通知来到,它自动会更新。

1
2
3
public interface Observer {
void update(String news); // 通知内容作为参数传递进来
}

假设有个新闻爱好者,想订阅新闻:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class NewsObserver implements Observer {
private String news;

// update 是在报社那里被调用的
@Override
public void update(String story, String news) {
this.news = news;
displayNews();
}

public void displayNews(){
System.out.println(this.getClass().getName() + "获取到:" + this.news);
}
}

同理,小说爱好者,想订阅小说:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StoryObserver implements Observer {
private String story;

@Override
public void update(String story, String news) {
this.story = story;
displayStory();
}

public void displayStory(){
System.out.println(this.getClass().getName() + "获取到:" + this.story);
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {

// 初始化主题
Publisher dailyPublisher = new Publisher();

// 初始化观察者
Observer storyObserver = new storyObserver();
Observer newsObserver = new NewsObserver();

// 注册观察者
dailyPublisher.registerObserver(storyObserver);
dailyPublisher.registerObserver(newsObserver);

// 发布消息,观察者自动会收到
dailyPublisher.setMessages("最新小说", "每日新闻");
}

结果:

1
2
StoryObserver获取到:最新小说
NewsObserver获取到:每日新闻

Java 内置的观察者模式

在 java.util 包内,自带了 Observer接口Observable类,跟我们自己实现的观察者模式大同小异。但是,jdk内置的主题是继承Observable类,而不是实现接口。但是在 java 9 中, 已经被标记为 deprecated,原因是,他们的扩展性不够好,可以用 Listeners 代替。见 Observer is deprecated in Java 9. What should we use instead of it?


  • 参考:《Head First 设计模式》