从零天梯:设计模式之观察者模式

学习观察者模式的时候发现自己有很多不懂,主要是平时项目没有用到,所以比较陌生。工作之余抓着间隙虚心向同事讨教了几招,整理了一下自己的近期学习笔记。如有纰漏,欢迎留言&评论~~

1 业务场景

了解观察者模式,咱们可以先看看这段代码。

1
2
3
$('#btn').on('click', function() {
//回调函数
});

使用jQuery的同学对这段代码都很熟悉吧~~
监听#btn的click事件并给予回调。很早的时候,业务逻辑我是直接写在回调函数里的。然而业务变复杂后,
这种写法的短板也就出来了,程序结构不清晰,耦合度高,代码重用性低等等。后来我尝试了这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function A() {
//业务逻辑
}
function B() {
//业务逻辑
}
$('#btn1').on('click', function() {
A();
B();
...
});
$('#btn2').on('click', function() {
A();
B();
...
});

剥离业务逻辑到外部函数,然后在回调函数里调用外部函数。同时,剥离出来的代码其他地方也能调用。
但是这样还不是最完美的,当类似 function A(), function B()的公共函数变得很多时,程序就变得很难管理,
所以我们就需要一个事件管理中心(观察者模式)对这些方法进行统一管理(分类、订阅、发布、销毁)

2 观察者模式概要

2.1 什么是观察者模式

观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听同一主题对象,这个主题对象的状态发生变化时,就会通知所有的观察者对象,使得它们能够自动更新自己。

2.2 观察者模式作用和注意事项
  • 模式作用:

    • 支持简单的广播通信,自动通知所有已经订阅过的对象。(全局通知
    • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。(等待被调用)
    • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。(模块化)
  • 注意事项:

    • 触发事件之前需预选订阅事件。

3 观察者模式核心实现

3.1 实现思路

举个生活中的例子,观察者模式有点类似于报纸订阅中心,用户如果需要阅读报纸,就需要预先要在订阅中心订阅报纸,中心会有一份名单,记录某某某订阅了报纸,然后工作人员会按照名单把报纸投递到相应的用户手上.如果用户不再需要阅读,则可以在中心申请取消订阅.

那么我们可以整理出观察者模式与例子中的联系:

  • 订阅名单——存取订阅关系的数据(Data)
  • 用户向中心订阅报纸——订阅事件(sub)
  • 投递报纸——发布事件(pub)
  • 用户申请取消订阅报纸——取消订阅(unsub)

如果用代码展示他们之间的关系,可以用一个对象以key-value的形式保存关系。

1
2
3
4
eventList = {
'事件A': [functionA, functionB]
, '事件B': [functionC, functionD]
}

这样看来就很好理解了:

订阅事件(sub):生成一个键制度,key存放事件名,value存放函数的引用.
发布事件(pub):查找对应的key值,并将key对应的value里function都执行一遍
取消订阅(unsub):去掉key值及其对应的value值。

3.2 实现代码

构建一个事件管理器对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(function($, window, undefined) {
//构建一个事件管理器对象
window.EventCenter = {
o: $({}), //创建一个空jq对象,用来存储订阅关系数据
sub: function() { //订阅事件
var self = this;
//借助on函数绑定自定义事件
self.o.on.apply(self.o, arguments);
},
pub: function() { //发布事件
var self = this;
//借助trigger函数模拟触发
self.o.trigger.apply(self.o, arguments);
},
unsub: function() { //取消订阅事件
var self = this;
//借助off函数解除事件绑定
self.o.off.apply(self.o, arguments);
}
};
})(jQuery, window);

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//使用方法
//订阅事件,'/test/ls'为事件名称(事件频道)
EventCenter.sub('/test/ls', function() {
var event = arguments[0];
//事件对象
console.log(event);
//函数传入参数
console.log(arguments);
});
//点击发布事件按钮,触发事先订阅的事件
$('#btn01').on('click', function() {
var argument = ['param01','param02'];
EventCenter.pub('/test/ls', argument);
});

//点击取消订阅按钮(事件取消后,点击发布事件按钮失效)
$('#btn02').on('click', function() {
EventCenter.unsub('/test/ls');
});

查看完整代码请猛戳这里

4 参考资料

设计模式—订阅发布模式(Subscribe/Publish)
百度百科-观察者模式
设计模式:观察者模式
Js实现基于发布/订阅机制的事件管理器(观察者模式)