这几天看《JavaScript设计模式》看的云里雾里的,设计模式看似是具体的东西,却又抓不住。在想发布/订阅模式的形态时,开启新思路,有所收获。
化繁为简分析,倒推分析; 化简为繁,是实际项目。
实际场景
有一个函数,所传参数不同执行结果不同;
另一个函数,所传参数不同执行结果不同... 有很多参数
正常情况我们会把代码罗列下来,就像积木一样, 这样看起来整个代码比较杂乱,如果函数之间相互调用会更乱,也不易于维护。
有问题就要解决,聪明的前辈们根据现象,思考出从各个维度对代码进行优化,总结出使用频率高的方式方法,也就是设计模式。
设计模式其实是一种形式。
基于上述问题解决方法
倒推的方式,先实现后调用
模块功能
定义一个存放函数的对象topics
把实现不同功能的函数存放到定义的对象里,动态添加对象属性,对象每个属性是存放对应功能函数和其编号
*topics= {
"topic1":[{token:0, fn}],
"topic2":[{token:1, fn1}],
"topic3":[{token:2, fn2}],
"topic3":[{token:3, fn2}]
}
定义一个全局对象,把处理上述添加对应的执行函数,以及根据参数执行功能函数挂载到这个对象上。
// 定义一个全局对象,挂载处理函数事件
let pubsub = {};
// 定义一个立即执行的匿名函数,生成独立的作用域, es6中可以使用{}形成独立的作用域,但是不能传参
(function (q) {
let topicObj = {},
subUid = -1;
// 订阅方法,也是添加函数的方法
// topic是作为动态的属性名, fn是对应的执行函数
q.subscribe = (topic, fn) =>{
// 判断topicObj对象中是否有对应的topic属性,如果没有则设置为数组
if(!topicObj[topic]){
topicObj[topic] = []
}
// 下标计算,是属性值,所以要转化为字符串
let token = (++subUid).toString()
// 添加到数组中
topicObj[topic].push({
token:token,
fn:fn
})
//console.log( topicObj )
//return唯一的标识符token,用于删除指定的项
return token;
}
// 发布方法,也是执行函数
q.publish = (topic, args)=> {
if(!topicObj[topic])return;
// 获取指定topic属性项,并获取长度
let subscribes = topicObj[topic],
len = subscribes.length;
//console.log(--len);
// 遍历并执行
while (len--){
// 回调函数有2个参数,一个表示属于对像的属性,另一个则是变量,在定义函数的时候要注意
subscribes[len].fn(topic, args);
}
return this;
}
// 删除订阅者,即对象中指定的属性,也就是对应动态添加的函数
q.delScribe = (token)=>{
for(let key in topicObj){
topicObj[key].forEach((item, i)=>{
if(item.token===token){
topicObj[key].splice(i,1)
}
})
}
console.log( topicObj )
return this;
}
})(pubsub);
//console.log(pubsub);
//测试
let msg = (data)=>{
// 这里还可以执行其它相关的函数
console.log('data---',data);
}
pubsub.subscribe('test', msg);
pubsub.publish('test', '这是数据');
//pubsub.delScribe('0');
~~~~匿名函数的使用,也是很有意思的。 不过是不很眼熟, jQuery框架使用的方式
(function(window){
jquery=function(){} // 相关代码
window.jquery = jquery;
})(window)
《JavaScript设计模式》之 publish/subscribe(发布/订阅)模式