生活中的釋出訂閱模式
小潘、小黃、小李都想要買部奧迪A4,一起去本市唯一一家4S店卻被告知沒有現車。4S店說:"如果您幾位不著急的話,我們可以從上海給調車,這可能需要等上個幾天(具體時間也不知道),幾位方便的話留個聯絡方式,一到車我會第一時間通知各位"。於是這3人在登記表上了留下了聯絡方式一些配置要求...在一個禮拜過後,車到了,4S店根據登記表一一聯絡了小潘、小黃、小李前來取車。
釋出訂閱的作用
上面的例子中,這3位留下聯絡方式,4S店一一通知他們(一對多的關係)前來取車就是一個典型的釋出訂閱模式。小潘,小黃,小李都是訂閱者,他們訂閱了車子到店的資訊,4S店作為釋出者,會在車子到店釋出資訊給訂閱者。
一步一步實現釋出訂閱
經過上面的例子,想必您對釋出訂閱模式或許有了些感官上的認識。如果還是覺得很模糊的話,那就跟著我一步一步來實現一個釋出訂閱。
動手之前的準備:
- 首先要指定釋出者(就像4S店)
- 然後要給一個快取列表,用於存放回撥函式以便告知訂閱者(就類似 登記表)
- 最後要釋出訊息的時候,釋出者會遍歷快取列表,依次觸發回撥函式(4S店打登記表上的電話,通知他們前來取車)。
- 第一段程式碼
function Sale(){//指定釋出者 定義一個4S店類
this._typeList = {};//定義快取列表 存放回撥函式
};
複製程式碼
為什麼把快取列表定義成物件{}?
答:就像現實中的買車,不同的消費者會需要不同品牌的汽車,{'奧迪','大眾','別克',....},4S店也經常
會遇到沒有現車的情況,所以就需要登記不同品牌的需求。並且,許多購車人都想知道訂購車的一些配置,
比如小潘訂閱了一部奧迪,他在登記表中新增了一些他關心的配置(比如:動力,油耗,空間...)這些配置就
類似回撥函式----奧迪:[動力,油耗,空間];等車子一到,4S店也會將相關配置告知小潘。複製程式碼
2.第二段程式碼
Sale.prototype.on = function(type,fn){//指定並增加訂閱者
if(!this._typeList[type]){//如果還沒有訂閱過此訊息,就給他建立一個快取列表 就像小潘
他們剛走,4S店來了一個人要邁巴赫,店裡也沒有現車,於是又在登記表上登記了
this._typeList[type] = [];
}
this._typeList[type].push(fn);
};複製程式碼
3.第三段程式碼
Sale.prototype.emit = function(type,...arg){ //釋出訊息 車子一到店 就通知人取車
if(this._typeList[type]){//如果之前有過此訂閱型別
this._typeList[type].forEach(item=>item(...arg))//執行回撥
}else {//如果沒有訂閱 直接返回
return false
}
};複製程式碼
4.前三段程式碼合併
function Sale(){
this._typeList = {};
};
Sale.prototype.on = function(type,fn){
if(!this._typeList[type]){
this._typeList[type] = [];
}
this._typeList[type].push(fn);
};
Sale.prototype.emit = function(type,...arg){
if(this._typeList[type]){
this._typeList[type].forEach(item=>item(...arg))
}else {
return false
}
};
var _4S = new Sale();
function fuel(who) { //小潘需要4s店在A4到車後,告知油耗
console.log('尊敬的'+who +'油耗=6.2-7.8L/100km');
}
function power(who) {//小潘需要4s店在A4到車後,告知其這車子的動力
console.log('尊敬的'+who+'發動機=2.0T');
}
_4S.on('A4',fuel)//購車者XXX向4S店訂閱了 A4的訊息
_4S.on('A4',power)
_4S.emit('A4','小潘')//4S店向小潘釋出A4的訊息複製程式碼
突然不想要A4了
有時候,我們也許突然之間,不想再獲得我們訂閱的訊息,這時候就需要設定取消訂閱的功能。 小潘不想要A4了...
Sale.prototype.remove = function(type,fn){
var len = this._typeList[type];
if(!len){//如果這款品牌的車的沒人訂閱過 直接返回
return false
}
if(!fn){//如果小潘沒有指定 4S店在A4到店後,要把哪些配置發給他(也即沒有傳入具體的回撥函式),則表示取消type對應的所有訂閱
len = null;
}else{
for(var i = len.length-1;i>=0;i--){
var _fn = len[i];
if(_fn === fn){
len.splice(i,1);//刪除訂閱的回撥函式
}
}
}
}複製程式碼
全部的程式碼
function Sale(){
this._typeList = {};
};
Sale.prototype.on = function(type,fn){
if(!this._typeList[type]){
this._typeList[type] = [];
}
this._typeList[type].push(fn);
};
Sale.prototype.emit = function(type,...arg){
if(this._typeList[type]){
this._typeList[type].forEach(item=>item(...arg))
}else {
return false
}
};
Sale.prototype.remove = function(type,fn){ var len = this._typeList[type];
if(!len){//如果這款品牌的車的沒人訂閱過 直接返回
return false
}
if(!fn){//如果小潘沒有指定 4S店在A4到店後,要把哪些配置發給他(也即沒有傳入具體的回撥函式),
則表示取消type對應的所有訂閱
len.length = 0
}else{
for(var i = len.length-1;i>=0;i--){
var _fn = len[i];
if(_fn === fn){
len.splice(i,1);//刪除訂閱的回撥函式
}
}
}
}
var _4S = new Sale();
function fuel(who) { //小潘需要4s店在A4到車後,告知油耗
console.log('尊敬的'+who +'油耗=6.2-7.8L/100km');
}
function power(who) {//小潘需要4s店在A4到車後,告知其這車子的動力
console.log('尊敬的'+who+'發動機=2.0T');
}
_4S.on('A4',fuel)//購車者XXX向4S店訂閱了 A4的訊息
_4S.on('A4',power)
_4S.on('A5',power)console.log(_4S._typeList); _4S.remove('A4',fuel)
_4S.emit('A4','小潘')//4S店向小潘釋出A4的訊息複製程式碼