我們需要弄清楚,觀察者模式和發布訂閱模式是不一樣的,一張圖理解:
兩者區別:
1. 觀察者 模式只有觀察者和被觀察者兩者,是松耦合
2. 發布訂閱模式除了發布者和訂閱者外,還有一個調度中心,是解耦的,兩者沒有直接關系
3. 觀察者主要是同步方式實現,二發布訂閱模式多數是異步實現,比如消息隊列
用typescript 簡單實現一個發布訂閱模式的類
1 class byEvent { 2 Events: { [key: string]: Array<Function> } //約束示例:{"eventName":[function(){},function(){},.....],......} 3 constructor() { 4 this.Events = {} 5 } 6 /** 7 * 發布/ 觸發 8 * @param eventName 9 * @param args 10 */ 11 emit(eventName: string, ...args: any) { 12 let callbackList = this.Events[eventName] || []; 13 callbackList.forEach(fn => fn.apply(this, args)) 14 return this; 15 // 如果用js寫,遍歷的時候要做一下判斷是否是函數,ts 用類型約束,在調用或者編譯階段會檢測是否合法 16 // callbackList.map(fn=>{ 17 // if(typeof fn==="function") fn.apply(this,args) 18 // }) 19 } 20 /** 21 * 訂閱/監聽 22 * @param eventName 23 * @param callback 24 */ 25 on(eventName: string, callback?: Function) { 26 // if(!eventName||typeof eventName !=="string") return ;// 因為用了ts 寫,所以這句不用寫了,如果是js寫,建議加這判斷 27 let callbackList = this.Events[eventName] || []; 28 callback && callbackList.push(callback) 29 this.Events[eventName] = callbackList 30 return this; 31 32 } 33 /** 34 * 只訂閱一次/監聽一次: 35 * 思路: 36 * 1. 重新包裝一個回調函數(有名的),進行注冊訂閱/監聽, 37 * 2. 包裝函數里面直接調用 once方法的第二個參數回調函數,然后調用off方法 卸載該包裝函數 38 * @param eventName 39 * @param callback 40 */ 41 once(eventName: string, callback?: Function) { 42 // if(!eventName||typeof eventName !=="string") return ; 43 let decor = (...args: any[]) => { 44 callback && callback.apply(this, args) 45 this.off(eventName, decor) 46 } 47 this.on(eventName, decor) 48 return this; 49 50 } 51 /** 52 * 卸載/取消 某一個回調監聽(不是取消eventName的所有回調監聽),主要配合once一起,實例單獨調用,無意義 53 * @param eventName 54 * @param callback 55 */ 56 off(eventName: string, callback: Function) { 57 let callbackList = this.Events[eventName] || []; 58 let resCallbacks = callbackList.filter(fn => fn !== callback) 59 this.Events[eventName] = resCallbacks 60 return this; 61 62 } 63 /** 64 * 卸載/取消 指定eventName 的所有訂閱/監聽 65 * @param eventName 66 * @param callback 67 */ 68 remove(eventName: string, callback?: Function) { 69 this.Events[eventName] = []; 70 callback && callback() 71 return this; 72 73 } 74 75 } 76 77 // 使用示例 78 let o = new byEvent() 79 setInterval(() => { 80 o.emit("name", 123) 81 o.emit("name", 10, 20) 82 o.emit("post", { name: 1212 }, "post") 83 84 }, 1000); 85 setTimeout(() => { 86 o.remove("name", function () { 87 console.log("remove") 88 }) 89 }, 3000) 90 o.once("name", function (...res: any[]) { 91 console.log("once-name1", res) 92 }) 93 o.on("name", function (...res: any[]) { 94 console.log("on-name2", res) 95 }) 96 o.on("post", function (...res: any[]) { 97 console.log("on-post", res) 98 }