在網(wǎng)上看到許多關(guān)于觀察者模式和發(fā)布訂閱模式的博文,發(fā)現(xiàn)很多人都認(rèn)為觀察者模式即發(fā)布訂閱模式,經(jīng)過(guò)進(jìn)一步的學(xué)習(xí)和理解,我認(rèn)為觀察者模式和發(fā)布訂閱模式還是有一些區(qū)別的,下面談?wù)勎覍?duì)觀察者模式和發(fā)布訂閱模式的理解「PS:歡迎各路大神指正」。
觀察者模式(Observer)
觀察者模式指的是一個(gè)對(duì)象(Subject)維持一系列依賴于它的對(duì)象(Observer),當(dāng)有關(guān)狀態(tài)發(fā)生變更時(shí) Subject 對(duì)象則通知一系列 Observer 對(duì)象進(jìn)行更新。
在觀察者模式中,Subject 對(duì)象擁有添加、刪除和通知一系列 Observer 的方法等等,而 Observer 對(duì)象擁有更新方法等等。
在 Subject 對(duì)象添加了一系列 Observer 對(duì)象之后,Subject 對(duì)象則維持著這一系列 Observer 對(duì)象,當(dāng)有關(guān)狀態(tài)發(fā)生變更時(shí) Subject 對(duì)象則會(huì)通知這一系列 Observer 對(duì)象進(jìn)行更新。
function Subject(){
this.observers = [];
}
Subject.prototype = {
add:function(observer){ // 添加
this.observers.push(observer);
},
remove:function(observer){ // 刪除
var observers = this.observers;
for(var i = 0;i < observers.length;i++){
if(observers[i] === observer){
observers.splice(i,1);
}
}
},
notify:function(){ // 通知
var observers = this.observers;
for(var i = 0;i < observers.length;i++){
observers[i].update();
}
}
}
function Observer(name){
this.name = name;
}
Observer.prototype = {
update:function(){ // 更新
console.log('my name is '+this.name);
}
}
var sub = new Subject();
var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');
sub.add(obs1);
sub.add(obs2);
sub.notify(); //my name is ttsy1、my name is ttsy2
上述代碼中,我們創(chuàng)建了 Subject 對(duì)象和兩個(gè) Observer 對(duì)象,當(dāng)有關(guān)狀態(tài)發(fā)生變更時(shí)則通過(guò) Subject 對(duì)象的 notify 方法通知這兩個(gè) Observer 對(duì)象,這兩個(gè) Observer 對(duì)象通過(guò) update 方法進(jìn)行更新。
在 Subject 對(duì)象添加了一系列 Observer 對(duì)象之后,還可以通過(guò) remove 方法移除某個(gè) Observer 對(duì)象對(duì)它的依賴。
var sub = new Subject();
var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');
sub.add(obs1);
sub.add(obs2);
sub.remove(obs2);
sub.notify(); //my name is ttsy1
發(fā)布訂閱模式(Publisher && Subscriber)
發(fā)布訂閱模式指的是希望接收通知的對(duì)象(Subscriber)基于一個(gè)主題通過(guò)自定義事件訂閱主題,被激活事件的對(duì)象(Publisher)通過(guò)發(fā)布主題事件的方式通知各個(gè)訂閱該主題的 Subscriber 對(duì)象。
let pubSub = {
list:{},
subscribe:function(key,fn){ // 訂閱
if (!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(fn);
},
publish:function(){ // 發(fā)布
let arg = arguments;
let key = [].shift.call(arg);
let fns = this.list[key];
if(!fns || fns.length<=0) return false;
for(var i=0,len=fns.length;i<len;i++){
fns[i].apply(this, arg);
}
},
unSubscribe(key) { // 取消訂閱
delete this.list[key];
}
};
pubSub.subscribe('name', (name) => {
console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
console.log('your sex is ' + sex);
});
pubSub.publish('name', 'ttsy1'); // your name is ttsy1
pubSub.publish('sex', 'male'); // your sex is male
上述代碼的訂閱是基于 name 和 sex 主題來(lái)自定義事件,發(fā)布是通過(guò) name 和 sex 主題并傳入自定義事件的參數(shù),最終觸發(fā)了特定主題的自定義事件。
可以通過(guò) unSubscribe 方法取消特定主題的訂閱。
pubSub.subscribe('name', (name) => {
console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
console.log('your sex is ' + sex);
});
pubSub.unSubscribe('name');
pubSub.publish('name', 'ttsy1'); // 這個(gè)主題被取消訂閱了
pubSub.publish('sex', 'male'); // your sex is male
觀察者模式 VS 發(fā)布訂閱模式

觀察者模式與發(fā)布訂閱模式都是定義了一個(gè)一對(duì)多的依賴關(guān)系,當(dāng)有關(guān)狀態(tài)發(fā)生變更時(shí)則執(zhí)行相應(yīng)的更新。
不同的是,在觀察者模式中依賴于 Subject 對(duì)象的一系列 Observer 對(duì)象在被通知之后只能執(zhí)行同一個(gè)特定的更新方法,而在發(fā)布訂閱模式中則可以基于不同的主題去執(zhí)行不同的自定義事件。相對(duì)而言,發(fā)布訂閱模式比觀察者模式要更加靈活多變。
我認(rèn)為,觀察者模式和發(fā)布訂閱模式本質(zhì)上的思想是一樣的,而發(fā)布訂閱模式可以被看作是觀察者模式的一個(gè)進(jìn)階版。
設(shè)計(jì)模式只是一種思想,某一種設(shè)計(jì)模式都可以有很多種不同的實(shí)現(xiàn)方式,各種實(shí)現(xiàn)都有其優(yōu)劣之分,具體的實(shí)現(xiàn)方式需要基于不同的業(yè)務(wù)場(chǎng)景。上述是我對(duì)觀察者模式和發(fā)布訂閱模式學(xué)習(xí)之后的一些理解,望指正。