一 概念
发布—订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
二 现实中的发布订阅者模式
1.比如小红最近在淘宝网上看上一双鞋子,但是呢 联系到卖家后,才发现这双鞋卖光了,但是小红对这双鞋又非常喜欢,所以呢联系卖家,问卖家什么时候有货,卖家告诉她,要等一个星期后才有货,卖家告诉小红,要是你喜欢的话,你可以收藏我们的店铺,等有货的时候再通知你,所以小红收藏了此店铺,但与此同时,小明,小花等也喜欢这双鞋,也收藏了该店铺;等来货的时候就依次会通知他们;
在上面的故事中,可以看出是一个典型的发布订阅模式,卖家是属于发布者,小红,小明等属于订阅者,订阅该店铺,卖家作为发布者,当鞋子到了的时候,会依次通知小明,小红等,依次使用旺旺等工具给他们发布消息;
2.再比如,报社和读者也是典型的发布订阅者模式的一种,当报社一有新的报纸出版之后,就会告诉读者,我们新版报纸出来了,快来买啊。在这里,报社就是发布者,读者就是订阅者
三 代码实现
实现上面例子中 报社-读者 的发布订阅者模式
html
<body>
<input type="button" id="pub1" value="第一报社"><input type="text" id="txt1" value=''> <br>
<input type="button" id="pub2" value="第二报社"><input type="text" id="txt2" value=''> <br>
<input type="button" id="pub3" value="第三报社"><input type="text" id="txt3" value=''> <br>
<textarea name="" id="sub1" cols="30" rows="10"></textarea>
<textarea name="" id="sub2" cols="30" rows="10"></textarea>
</body>
//js
// 发布者
var Publish = function(name) {
this.name = name;
this.subscribers = []; //接受所有的订阅者(每一个元素是函数类型fn的数组)
}
// Publish类的实例对象发布消息的方法
Publish.prototype.deliver = function(news) {
var publish = this;
this.subscribers.forEach(function(fn) {
// 把新消息发给一个订阅者
fn(news, publish);
});
// 链式编程
return this;
}
// 具体的一个订阅者去订阅报纸的方法
Function.prototype.subscribe = function(publish) {
var suber = this; //当前订阅者
// 数组的some : 遍历数组中的元素,执行一个函数,有一个返回true、,整体返回true
// 检查当前这个人是不是已经订阅过了
var isExists = publish.subscribers.some(function(item) {
return item === suber;
});
if (!isExists) {
publish.subscribers.push(suber);
}
// 链式编程
return this;
}
// 取消订阅的方法
Function.prototype.unsubscribe = function(publish) {
var suber = this;
// filter 返回一个心数组,
// 去掉suber
publish.subscribers = publish.subscribers.filter(function(item) {
return item !== suber;
});
return this;
}
var pub1 = new Publish('第一报社');
var pub2 = new Publish('第二报社');
var pub3 = new Publish('第三报社');
// 定义 2个订阅者
var sub1 = function(news) {
document.getElementById('sub1').innerHTML += arguments[1].name + '~~~' + news + '\n';
}
var sub2 = function(news) {
document.getElementById('sub2').innerHTML += arguments[1].name + '~~~' + news + '\n';
}
// 执行订阅方法
sub1.subscribe(pub1).subscribe(pub2).subscribe(pub3);
sub2.subscribe(pub1).subscribe(pub2);
// 事件绑定
document.getElementById('pub1').onclick = function() {
pub1.deliver(document.getElementById('txt1').value)
}
document.getElementById('pub2').onclick = function() {
pub2.deliver(document.getElementById('txt2').value)
}
document.getElementById('pub3').onclick = function() {
pub3.deliver(document.getElementById('txt3').value)
}
sub1.unsubscribe('pub1');