观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
支持简单的广播通信,自动通知所有已经订阅过的对象。
页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
首先来一个例子,利用js原型特性实现观察者模式:
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe:function(fn) {
var that = this;
that.fns.push(fn);
},
unsubscribe:function(fn) {
var that = this;
that.fns = that.fns.filter(function(el){
if (el != fn) {
return el;
}
});
},
update:function(o,thisObj) {
var scope = thisObj || window;
this.fns.forEach(function (el) {
el.call(scope, o);
}
);
}
}
var o = new Observer;
var f1 = function (data) {
console.log('bry1: ' + data + ', 赶紧干活了!');
};
var f2 = function (data) {
console.log('bry2: ' + data + ', 找他加点工资去!');
};
o.subscribe(f1);
o.subscribe(f2);
o.update("老板回来了!")
//退订f1
o.unsubscribe(f1);
//再来验证
o.update("老板回来了!");
输出结果
bry1: 老板回来了!, 赶紧干活了!
index.html:123 bry2: 老板回来了!, 找他加点工资去!
index.html:123 bry2: 老板回来了!, 找他加点工资去!
再来一种创建形式,利用对象创建观察者模式
var pubsub = {
topics : {}, // 回调函数存放的数组
subUid : -1,
//订阅方法
subscribe : function (type, func) {
if (! this.topics[type]) {
this.topics[type] = [];
}
var token = (++ this.subUid).toString();
this.topics[type].push({
token: token,
func: func
});
return token;
},
// 发布方法 -- 通知
publish : function (type, args) {
var that = this;
if (! that.topics[type]) {
return false;
}
setTimeout(function () {
var subscribers = that.topics[type],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(type, args);
}
}, 0);
return true;
},
//退订方法
unsubscribe : function (token) {
for (var m in this.topics) {
if (this.topics[m]) {
for (var i = 0, j = this.topics[m].length; i < j; i++) {
if ( this.topics[m][i].token === token) {
this.topics[m].splice(i, 1);
return token;
}
}
}
}
return false;
}
};
//来,订阅一个
pubsub.subscribe('example1', function (type, data) {
console.log(type + ": " + data);
});
pubsub.subscribe('example1', function (type, data) {
console.log("brydemo-" + type + ": " + data);
});
pubsub.subscribe('example2', function (type, data) {
console.log("订阅的第二种类型-" + type + ": " + data);
});
//发布通知
pubsub.publish('example2', 'hello world!');
输出结果:
订阅的第二种类型-example2: hello world!