②发布+订阅=观察者模式

像广播一样发消息

思考一个问题,有没有一种可能,另一个人A,不知道你这个人的存在,但是却可以给你发消息。A 就像是一个广播站一样,将你们联系在一起的就是手中的收音机,你等待着 A 发布消息,而你等待消息就是一个订阅的行为。

或者换一种说法,你就像是一个观察者一样,观察消息有没有到来。无论哪种定义无非都是在描述一种关系,接受消息者和发送消息者之间的关系。

下面要实现一个新闻广播站,每当有新的新闻,会调用新闻对象的broadcastNews,并向观察者们推送消息。下面是一个非常不好的写法:

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
interface Observer {
update(message?: { news: string[] }): void;
}

class NewsObserver implements Observer {
update(message): void {
console.log(message);
}
}

const new1 = new NewsObserver();
const new2 = new NewsObserver();

interface Subscribe {
register(observer: Observer): void;
unregister(observer: Observer): void;
getWeather(city: string): NewsInfo;
notify(): void;
}

class NewsSubscribe {
getNews() {
return "获取到新闻";
}
broadcastNews() {
const news = this.getNews();
new1.update(news);
new2.update(news);
}
}

const newsSubscribe = new NewsSubscribe();

这种写法存在着很多严重的问题:

  • 观察者与被观察者紧耦合在了一起
  • 没办法在程序执行的时候动态添加或删除观察者
  • 观察者是会动态变化的对象,但是没有独立且封装

设计观察者模式

首先我们让被观察者有注册观察者和取消注册观察者的能力。这样能让观察者与被观察者解耦,并在程序执行的时候动态的添加或删除。

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class NewsSubscribe implements Subscribe {
private observerList: Observer[];
constructor() {
this.observerList = [];
}
register(observer: Observer): void {
this.observerList.push(observer);
}

unregister(observer: Observer): void {
const index = this.observerList.indexOf(observer);
if (index > 0) {
this.observerList.splice(index, 1);
}
}
notify(): void {
this.observerList.forEach((observer) => {
observer.update();
});
}
}

被观察者不知道观察者的细节,只知道观察者实现了观察者接口。

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
interface NewsInfo {
news: string[];
}

interface Observer {
update(subscribe: NewsSubscribe): void;
}

class NewsObserver implements Observer {
update(subscribe: NewsSubscribe): void {
console.log(subscribe.getNews());
}
}

const new1 = new NewsObserver();

interface Subscribe {
register(observer: Observer): void;
unregister(observer: Observer): void;
getNews(city: string): NewsInfo;
notify(): void;
}

class NewsSubscribe implements Subscribe {
private observerList: Observer[];
constructor() {
this.observerList = [];
}
register(observer: Observer): void {
this.observerList.push(observer);
}

unregister(observer: Observer): void {
const index = this.observerList.indexOf(observer);
if (index > 0) {
this.observerList.splice(index, 1);
}
}

notify(): void {
this.observerList.forEach((observer) => {
observer.update(this);
});
}

getNews(): NewsInfo {
return {
news: ["新闻"],
};
}
}

const newsSubscribe = new NewsSubscribe();
newsSubscribe.register(new NewsObserver());
newsSubscribe.register(new NewsObserver());

newsSubscribe.notify();
  • 可以为观察者模式设置 setChanged hasChanged 方法,此方法可以控制通知的条件,避免通知的频率过高
  • 观察者模式定义了对象之间一对多的关系。主题 (也就是可观察者) 用共同的接口来更新观察者
  • 观察者和可观察者之间用松耦合方式结合 (loosecoupling),可观察者不知道观察者的细节,只知道观察者实现了观察者接口。
    有弹
  • 使用此模式时,你可从被观察者处推 (push)或拉 (pul1)数据(然而,推的方式被认为更“正确”)。
  • 有多个观察者时,不可以依赖特定的通知次序
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2025 SunZhiqi

此时无声胜有声!

支付宝
微信