觀察者模式又叫發佈訂閱模式(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!