>[success] # 发布订阅模式实现通用模型 ~~~ 1.刚才的代码有个问题不能复用,将代码封装复用(js设计模式与开发实践书中例子) ~~~ >[danger] ##### 代码实现 ~~~ 1.下面代码定义了一个'event' 对象,这个对象是一个发布订阅模型, 然后定义了一个方法'installEvent' 给那些需要发布订阅模型的对象赋值 2.也可以用继承的方式 ~~~ ~~~ 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) fns = this.clientList[key] if(!fns||fns.length ===0){ return false } for(var i=0 ,fn;fn=fns[i++];){ fn.apply(this,arguments) } } } // installEvent 用来给所有函数增加动态安装发布功能 var installEvent = function (obj) { for(var i in event){ obj[i] = event[i] } } // 声明一个售楼处对象 salesOffices var salesOffices = {} installEvent(salesOffices) salesOffices.listen('squareMeter88',function (price) { console.log('价格='+price) }) salesOffices.listen('squareMeter188',function (price) { console.log('价格='+price) }) salesOffices.trigger('squareMeter88',200000) salesOffices.trigger('squareMeter188',300000) ~~~ >[danger] ##### 进一步去完善这个发布订阅模式 -- 取消订阅事件 ~~~ 1.现在我们有发布对象他的构成: 1.1.'用来缓存对象的属性', 1.2.'用来记录订阅者需求,并且把这些需求记录到缓存对象中' 1.3.'用来发布对应消息的方法' 2.如果我虽然订阅了,但突然想取消接受,这时候我们需要做一个'取消订阅事件' 3.增加一个取消订阅事件需要考虑,三点 3.1.如果要取消的事件本身不存在 3.2.如果没有指定要取消的具体事件 3.2.如果找到了具体订阅事件回调 ~~~ ~~~ /** * 1.做一个发布者 * 1.1.储存订阅者的地方 -- 数据库类似 * 1.2.保存这些订阅者 -- 新增 * 1.3.可以删除这些订阅者 -- 删除 * 1.4.同意调用这些订阅者 -- 符合定义一个对象改变,其依赖对象发生变化 * **/ 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) fns = this.clientList[key] if(!fns||fns.length ===0){ return false } for(var i=0 ,fn;fn=fns[i++];){ fn.apply(this,arguments) } } } // 增加了一个取消订阅方法 event.remove = function( key, fn ){ var fns = this.clientList[ key ]; if ( !fns ){ // 如果 key 对应的消息没有被人订阅,则直接返回 return false; } if ( !fn ){ // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅 fns && ( fns.length = 0 ); }else{ for ( var l = fns.length - 1; l >=0; l-- ){ // 反向遍历订阅的回调函数列表 var _fn = fns[ l ]; if ( _fn === fn ){ fns.splice( l, 1 ); // 删除订阅者的回调函数 } } } }; var salesOffices = {}; var installEvent = function( obj ){ for ( var i in event ){ obj[ i ] = event[ i ]; } } installEvent( salesOffices ); salesOffices.listen( 'squareMeter88', fn1 = function( price ){ // 小明订阅消息 console.log( '价格= ' + price ); }); salesOffices.listen( 'squareMeter88', fn2 = function( price ){ // 小红订阅消息 console.log( '价格= ' + price ); }); salesOffices.remove( 'squareMeter88', fn1 ); // 删除小明的订阅 salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000 ~~~