什麼是釋出訂閱模式
釋出-訂閱模式又叫做觀察者模式。他定義了一種一對多的依賴關係,即當一個物件的狀態發生變化的時候,所有依賴的物件都會得到通知。
基本實現
把自己想象成公司的祕書,領導需要開一個會議,需要你去通知所有參會人員;
這裡有幾個元素:
- 釋出者(祕書)
- 與會人員(需要參加會議的人員)
還有幾個方法:
- 製作與會人員名單
- 刪除不參加的人
- 傳送會議通知,以及必要的時間地點等資訊
你首先需要把所有的與會人員名單收集起來(也就是新增依賴函式),然後根據清單傳送通知,並攜帶必要的會議資訊,與會人員收到資訊後會做出相應的反應(回撥函式中的處理邏輯)
let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (fn) {
this.peopleList.push(fn);
}
yourMsg.triger = function () {
let that = this
let args = arguments
setTimeout(function() {
for(let i = 0,fn;fn=that.peopleList[i++];){
fn.apply(that,args);
}
},2000)
}
yourMsg.listen(function () {
console.log('我被通知了,我回去參加會議,給我時間地點')
console.log(`title:${arguments[0]}`);
console.log(`time:${arguments[1]}`);
})
yourMsg.listen(function () {
console.log('我被通知了,但是我不care')
})
yourMsg.listen(function () {
console.log('我被通知了,Jack代替我去')
})
yourMsg.triger('會議', '3:00');
複製程式碼
這便是一個簡單的訂閱釋出模式
分主題的訂閱釋出模式
隨著公司業務量的增加,你的會議不需要所有人都參加,你需要分主題維護一份參會人員名單;
比如,產品會議需要小A,小B參加;而技術會議需要小C,小D參加;
這裡我們通過在新增與會人員的時候新增一個‘key’值代表該成員需要參加的會議型別;
let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (key, fn) {
if (!this.peopleList[key]) {
this.peopleList[key] = [] // 如果分類中沒有此型別的訊息,則新建一個
}
this.peopleList[key].push(fn);
}
yourMsg.triger = function () {
let key = Array.prototype.shift.call(arguments)
let fns = this.peopleList[key]
let that = this
let args = arguments
if (!fns) {
return false
}
setTimeout(function() {
for(let i = 0,fn;fn=fns[i++];){
fn.apply(that,args);
}
}, 200)
}
yourMsg.listen('prod', function () {
console.log('小A: 我只關心會議訊息,其它的事別來煩我')
console.log(`title:${arguments[0]}`);
console.log(`time:${arguments[1]}`);
})
yourMsg.listen('prod', function () {
console.log('小B: 會議使我精神百倍!')
console.log(`title:${arguments[0]}`);
console.log(`time:${arguments[1]}`);
})
yourMsg.listen('tech', function () {
console.log('小C:我只關心技術會議,產品會議讓那些傻瓜去吧')
})
yourMsg.listen('tech', function () {
console.log('小D:又到技術會議時間了?我是被逼的!')
})
yourMsg.triger('prod', '開會啦', '下午3:00');
yourMsg.triger('tech');
複製程式碼
可以隨處呼叫的訂閱釋出功能
由於你們公司效益特別好,你一個祕書已經忙不過來,這個時候,公司又來了一位祕書。你只需要把你通知會議安排的方法告訴他,讓他按照這個模式去做就好了。
這裡我們並沒有用物件來做,而是通過Object.Create()通過依賴關係來實現類似繼承的效果;更加的合理簡潔;個人我認為在js中完全沒必要也不應該使用物件導向的模式,因為它壓根就麼有所謂的物件導向,相比於東施效顰不如發揮自己的特點。
let installer = {
peopleList: [],
listen (key, fn) {
if (!this.peopleList[key]) {
this.peopleList[key] = [] // 如果分類中沒有此型別的訊息,則新建一個
}
this.peopleList[key].push(fn);
},
triger () {
let key = Array.prototype.shift.call(arguments)
let fns = this.peopleList[key]
let that = this
let args = arguments
if (!fns) {
return false
}
setTimeout(function() {
for(let i = 0,fn;fn=fns[i++];){
fn.apply(that,args);
}
}, 200)
},
remove (key, fn) {
let fns = this.peopleList[key]
if (!fns) {
return false
}
for (let index = 0; index < fns.length; index++) {
const _fn = fns[index];
if(_fn === fn){
fns.splice(index,1);
}
}
}
}
let yourMsg = Object.create(installer);
yourMsg.listen('prod', function () {
console.log('小A: 我只關心會議訊息,其它的事別來煩我')
console.log(`title:${arguments[0]}`);
console.log(`time:${arguments[1]}`);
})
yourMsg.listen('prod', function () {
console.log('小B: 會議使我精神百倍!')
console.log(`title:${arguments[0]}`);
console.log(`time:${arguments[1]}`);
})
let smA = function () {
console.log('小C:我只關心技術會議,產品開會讓那些傻瓜去吧')
}
let smB = function () {
console.log('小D:又到技術會議時間了?我是被逼的!')
}
yourMsg.listen('tech', smA)
yourMsg.listen('tech', smB)
yourMsg.remove('tech', smA)
yourMsg.triger('prod', '開會啦', '下午3:00');
yourMsg.triger('tech', smA);
複製程式碼