前言 现实中的发布-订阅模式
小明最近看上了一套房子,到了售楼处之后才被告知,该楼盘的房子早已售罄。好在售楼MM告诉小明,不久后还有一些尾盘推出,开发商正在办理相关手续,手续办好后就可以购买。但到底什么时候,目前还没有人知道。
于是小明记下了售楼处的电话,以后每天都会打电话过去询问是不是到了购买时间。除了小明,还有小红、小强、小龙也会每天向售楼处咨询这个问题。一个星期后,售楼MM决定辞职,因为厌倦了每天回答1000个相同内容的电话。
当然现实中没有这么笨的售楼公司,实际上故事是这样的:小明离开之前,把电话号码留在了售楼处。售楼MM答应他,新楼盘一推出就马上发信息通知小明。小红、小强、小龙也是一样,他们的电话号码都被记在售楼处的花名册上,新楼盘推出的时候,售楼MM会翻开花名册,遍历上面的电话号码,依次发送一条短信来通知他们。
一、最简单的例子
// 订阅信息
document.body.addEventListener('click', function(){
alert(1);
},false);
// 订阅信息
document.body.addEventListener('click', function(){
alert(2);
},false);
// 发布消息
document.body.click();
document.body订阅了click事件,然后当它被点击(发布)的时候,接收到了信息。
二、发布-订阅模式的模式简单实现
// 定义售楼处
var salesOffices = {};
// 售楼花名册
salesOffices.clientList = [];
// 订阅售楼消息的函数
salesOffices.listen = function (fn) {
this.clientList.push(fn);
}
// 发布售楼消息的函数
salesOffices.trigger = function () {
// 遍历花名册,给留了电话号码的客户发送信息
for (var i = 0, fn; fn = this.clientList[i++];) {
debugger;
fn.apply(this, arguments);
}
}
// 小明订阅售楼信息
salesOffices.listen(function (price) {
console.log('price=' + price);
});
// 小红订阅售楼信息
salesOffices.listen(function (price) {
console.log('price=' + price);
});
// 售楼处发布售楼信息
salesOffices.trigger('squareMeter88', 200000);
salesOffices.trigger('squareMeter110', 300000);
简单的发布-订阅模式存在一个缺陷:就是如果小明只想订阅88平米的楼盘,但是售楼处会把所有的楼盘信息都推送给了他。我们可以做得更智能一些,给订阅的函数多传一个参数,表明订阅者只订阅那一个消息。
三、发布-订阅模式的模式进阶实现
// 定义售楼处
var salesOffices = {};
// 定义客户花名册
salesOffices.clientList = [];
// 定义订阅方法
salesOffices.listen = function (key, fn) {
// 花名册登记哪些客户订阅哪些信息(根据key来区分)
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
}
salesOffices.trigger = function () {
// 获取key,获取第一个参数
var key = Array.prototype.shift.call(arguments);
var fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
}
// 小明定于88平米的楼盘
salesOffices.listen('squareMeter88', function (price) {
console.log('price=' + price);
});
// 小红定于100平米的楼盘
salesOffices.listen('squareMeter100', function (price) {
console.log('price=' + price);
});
// 售楼处发布楼盘信息
salesOffices.trigger('squareMeter88', 2000000);
salesOffices.trigger('squareMeter100', 3000000);
四、封装订阅-发布模式
var event = {
clientList: [],
listen: function(key, fn) {
if (!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
},
trigger: function() {
var key = Array.prototype.shift.call(arguments);
var fns = this.clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i=0,fn;fn=fns[i++];) {
fn.apply(this, arguments);
}
}
}
function installEvent(obj) {
for (var i in event) {
obj[i] = event[i];
}
}
var salesOffices = {};
installEvent(salesOffices);
salesOffices.listen('squareMeter88', function(price) {
console.log(`price=${price}`);
});
salesOffices.trigger('squareMeter88',200000);