观察者模式学习笔记

观察者模式,类结构图如下所示:

对象接口(被观察者)

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

/**
* 被观察者
*
* 有 添加,删除观察者的方法和更新观察者状态的方法
*/
public interface Subject {

void register(Observer observer);

void remove(Observer observer);

void send(String message);
}

观察者接口

1
2
3
4
5
6
7
8
9
package com.example.demo.design_pattern;

/**
* 观察者
*/
public interface Observer {

void receive(String message);
}

对象的实现类

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
package com.example.demo.design_pattern;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
* 被观察者
*
* 被观察者一般是内容提供者
*
* 有一个容器,来盛放所有的观察者
*
* 有 添加,删除观察者的方法和更新观察者状态的方法
*/
public class NewsPaper implements Subject {

List<Observer> users;

public NewsPaper() {
users = new ArrayList<>();
generateNews();
}

/**
* 模拟产生新闻,每个2s发送一次
*/
private void generateNews() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int titleCount = 1;
int contentCount = 1;

@Override
public void run() {
send("title:" + titleCount++ + "content:" + contentCount++);
}
}, 1000, 1000);
}

/**
* 注册用户(消费者)
* @param observer
*/
public void register(Observer observer) {
if (!users.contains(observer)) {
users.add(observer);
}
}

/**
* 移除用户(观察者)
* @param observer
*/
public void remove(Observer observer) {
if (users.contains(observer)) {
users.remove(observer);
}
}

/**
* 报社推送文章
*
* @param message
*/
public void send(String message) {
for (Observer observer: users) {
observer.receive(message);
}
}
}

核心方法:添加订阅者,删除订阅者,更新消息接口

观察者的实现类

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
package com.example.demo.design_pattern;

/**
* 被观察者
*
* 有一个容器,来盛放所有的观察者
*
*
* 有 添加,删除观察者的方法和更新观察者状态的方法
*/
public class User implements Observer{

private String id;

public User(String id) {
this.id = id;
}

/**
* 根据输出,每个用户都会受到报社每间隔一秒发送过来的信息
*
* @param message
*/
@Override
public void receive(String message) {
System.out.println(id + "收到的报社发送的消息是:" + message);
}
}

测试类:

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

/**
* 测试主函数
*/
public class ZTest {

public static void main(String[] args) {
NewsPaper newsPaper = new NewsPaper();
User user;
for (int i = 0; i < 10; i++) {
user = new User("user:"+i);
newsPaper.register(user);
}
}
}

核心方法:订阅接口、这个接口是每次被订阅者更新消息时:需要被被订阅者调用的接口,在这个接口里面订阅者实现具体的业务内容。

应用场景类似于:

  1. 报社的用户订阅报纸

    报社是对象,所有的用户是观察者,用户订阅报社的报纸期刊,然后报社发布期刊之后,用户收到报纸

  2. MVC 模式

    model 是对象,是被订阅者。view 是观察者,观察者监听model,如果 model 的内容发生了变化,那么view 监听到内容变化,更新视图的内容

  3. 互联网产品中的订阅模式

    微博里面的关注,只有关注了之后,被关注者发送了内容之后关注着才可以收到推送

  4. 前端的一些 MVVM 框架也有用到订阅-发布模式,类似于 Vue.js

观察者模式和 MVC 的关系详解

MVC模式是一种架构模式,它包含三个角色:模型(Model),视图(View)和控制器(Controller)。观察者模式可以用来实现MVC模式,观察者模式中的观察目标就是MVC模式中的模型(Model),而观察者就是MVC中的视图(View),控制器(Controller)充当两者之间的中介者(Mediator)。当模型层的数据发生改变时,视图层将自动改变其显示内容。

参考链接

面条先生 wechat
欢迎关注我的 “知乎日报” 小程序