发布-订阅模式(观察者模式)
来源:互联网 发布:流程 数据库设计 编辑:程序博客网 时间:2024/06/05 06:24
写在前面
参考文档《JavaScript设计模式与实战》
发布-订阅模式
光是看名字还是很好理解的,也就是在生活中,我们常常受到关于某品牌的活动消息(虽然大多数都是默认订阅),此时收到信息的我们就是订阅者,而品牌方则是发布者。
发布-订阅的模式也有很多好处:不需要我们每次都去询问活动什么时候举办。解耦的操作,品牌方不需要关心订阅者的其他消息,只需要按照名单发送短信即可。
主要的内容
我们可以看到这个模式中有三个主要的角色和内容:1. 发布者 2. 订阅者 3. 订阅名单列表
下面是实现
let saler = {};// 存放顾客名单saler.list = [];// 添加订阅消息的顾客saler.listen = function(fn) { this.list.push(fn);}// 发布消息saler.trigger = function() { for(let i in this.list) { this.list[i].apply(this, arguments); }}
实践
saler.listen(function(price, area) { console.log('price is '+price+' area is '+ area);})saler.trigger(200, 100); // price is 200 area is 100
有没有发现奇怪的一点?
就是,一旦saler发布一个消息,所有的订阅者都会收到消息,不论他们是否订阅了该消息。
我只想收到我需要的
于是乎,这就涉及到了分类问题。
因此,我们加上一个key
。这个key
是用与给订阅不同消息的用户进行分类,订阅相同消息的用户将使用同一个key进行订阅消息。
let saler = {};// 修改客户列表为对象,key为属性值,每个属性都维护一个顾客数组saler.list = {};saler.listen = function(key, fn) { if(!this.list[key]) { this.list[key] = []; } this.list[key].push(fn);}// 根据key来发布消息,这样只会发布到订阅相同key的顾客手机上saler.trigger = function() { let key = arguments[0]; if(!key || !this.list[key]) { return false; } for(let i in this.list[key]) { this.list[key][i].apply(this, arguments); }}
实践
saler.listen('Activity1', function(price, area) { console.log('It\'s ' + arguments[0]); console.log('price is '+arguments[1]+' area is '+ arguments[2]);})saler.listen('Activity2', function() { console.log('It\'s ' + arguments[0]); console.log('price is '+arguments[1]+' area is '+ arguments[2]);})// It's Activity1, price is ..saler.trigger('Activity1' ,200, 100); // It's Activity2, price is ..saler.trigger('Activity2' ,300, 300);// 什么都不输出saler.trigger('Activity3', 100, 100);
这就解决了订阅不同消息时发布到不同的顾客手中。
现在又出现了一个问题,如果有50个品牌方,手中都有顾客名单,也要发布相关活动信息,这样不是得写50个上面的对象?
因此需要实现一个通用的版本,即所有品牌方都可以通过某个对象上的方法进行发布内容。
通用版本
首先实现一个类,这个类中有上面所叙述的所有属性和方法。
let Saler = function(name) { this.name = name; this.list = {}; this.listen = function(key, fn) { if(!this.list[key]) { this.list[key] = []; } this.list[key].push(fn); }; this.trigger = function() { let key = arguments[0]; if(!key || !this.list[key]) { return false; } for(let i in this.list[key]) { this.list[key][i].apply(this, arguments); } };}
现在有两个品牌方,一个是Beauty
,另一个是Handsome
。他们通过new
来创建新的对象,这个对象有上述的所有方法。
let saler = new Saler('Beauty');let saler2 = new Saler('Handsome');
顾客订阅他们的活动
saler.listen('Activity1', function(price, area) { console.log('Name of Brand: '+ this.name); console.log('It\'s ' + arguments[0]); console.log('price is '+arguments[1]+' area is '+ arguments[2]);})saler2.listen('Activity1', function(price, area) { console.log('Name of Brand: '+ this.name); console.log('It\'s ' + arguments[0]); console.log('price is '+arguments[1]+' area is '+ arguments[2]);})
品牌方分别发布他们的活动
// "Name of Brand: Beauty"// "It's Activity1"// "price is 200 area is 100"saler.trigger('Activity1' ,200, 100);// "Name of Brand: Handsome"// "It's Activity1"// "price is 2000 area is 10"saler2.trigger('Activity1', 2000, 10);
不好意思,我要取消订阅
顾客是上帝,她说订就订,她说取消咱们也麻利点取消订阅。
显然,取消订阅只需要在她订阅的活动的名单中删除掉这个顾客就好了。
添加一个remove
方法。
this.remove = function(key, fn) { if(!key || !this.list[key]) { return false; } for(let i in this.list[key]) { if(this.list[key][i] === fn) { this.list[key].splice(i, 1); console.log(this.list); break; } } }
这里需要注意的是,由于取消订阅是通过判断两个函数是否相等进行的删除,因此在listen
时不能用匿名函数。
实践
saler.listen('Activity1', fn1 = function(price, area) { console.log('Name of Brand: '+ this.name); console.log('It\'s ' + arguments[0]); console.log('price is '+arguments[1]+' area is '+ arguments[2]);})saler.remove('Activity1', fn1);
- 观察者模式(也就是发布订阅模式)
- 观察者模式(发布订阅模式)
- 发布订阅模式(观察者模式)
- 发布-订阅模式(观察者模式)
- 观察者模式(发布订阅模式)
- 观察者模式(发布订阅模式)
- 观察者模式--发布/订阅模式
- 发布订阅(观察者)模式-c++
- 观察者(发布-订阅)模式浅析
- 监听器设计模式(观察者模式、订阅发布模式)
- Javascript设计模式-07-观察者模式(发布订阅模式)
- 设计模式二:观察者模式(发布订阅模式)
- 设计模式(三)观察者模式Observer(发布订阅)
- C++之观察者模式(订阅-发布模式)
- 观察者模式之二 -发布 订阅模式
- 观察者模式 (发布-订阅模式)
- 8. 观察者模式-发布订阅模式
- 观察者模式(又叫发布-订阅模式)
- Android 开发之 Kotlin 初始篇
- python-技术指标-ema算法
- Json解析的四种方法
- 如何将内存图像数据封装成QImage
- 17-JSCPC&&CCPC中南赛区 H-Highway 树的直径DFS
- 发布-订阅模式(观察者模式)
- 只具备内网的服务器通过yum安装软件
- P1047 校门外的树
- Android常用检查判断方法
- Guice注解实现一个类型绑定多个实现.
- 升级linux内核(2.6.32->3.10.105),安装docker
- 上机第十四周实验
- 今日头条lite:你关心的才是头条【极乐小程序商店出品】
- 在java web项目中调用c++程序简单案例