1、什麼是觀察者模式前端
觀察者模式,引用維基百科的說法,一個目標對象管理全部相依與它的觀察者對象,並在它自己狀態改變時發生通知。這一般經過調用各觀察者所提供的方法來實現。在前端應用的範圍還挺多,最多見的事件監聽,addEventListener,咱們在一個元素上註冊了各種事件,而當對象發生相應改變時,經過調用綁定的事件告訴觀察者。就至關於在一個對象上綁定了各種觀察者。java
舉個與前端不相關的例子,小偷警察的故事。小偷數量就是咱們這裏的目標對象,有三個警察負責看管(觀察者),當小偷數量大於3了,一個警察要去報告上級,一個警察要去警告市民引發重視,一個去和小偷談話。在程序裏經過調用這三個警察的方法來至關於告訴這三個警察小偷數量大於3了。設計模式
2、用代碼看觀察者模式思路dom
/* 被觀察類 addObserver()方法把觀察者對象添加到觀察者對象列表中 setChange()方法用來設置一個內部標誌位註明數據發生了變化 notifyObservers()方法會去調用觀察者對象列表中全部的Observer的update()方法,通知它們數據發生了變化。 */ function Observable(){ this.observerArray = new Set(); this.updateFlage = false; } Observable.prototype.addObserver = function(data){ this.observerArray.add(data); } Observable.prototype.setChange = function(){ this.updateFlage = true; } Observable.prototype.notifyObservers = function(data){ if(this.updateFlage){ for(let item of this.observerArray){ item.update(data) } } this.updateFlage = false } /* 觀察者類 實現Observer接口的惟一方法update */ function Observer(){ this.update = function(){ } }
皮一下,這實際上是看了Java裏的觀察者模式思想,我用Js實現了一下。由於我看這個實現思路是更能體會到觀察者模式的。這裏有兩個類,一個是被觀察類,實現了上述三個方法,一個是觀察者類。每一個觀察者都有update方法,當被觀察者改變了,執行相應的觀察者的update方法來通知觀察者被觀察者改變了。下面看示例:函數
function thief(){ var data = 0; Observable.call(this); this.setData = function(param){ data = param; if(data > 3){ this.setChange(); } this.notifyObservers(); } this.getData = function(){ return data } } thief.prototype = new Observable(); thief.prototype.constructor = thief; let thief1 = new thief(); let police1 = new Observer; let police2 = new Observer; thief1.addObserver(police1) thief1.addObserver(police2) police1.update = function(){ console.log('警察1接收到如今有'+thief1.getData()+'個小偷') } police2.update = function(){ console.log('警察2接收到如今有'+thief1.getData()+'個小偷') } thief1.setData(1) //無輸出 thief1.setData(4) //警察1接收到如今有4個小偷 警察2接收到如今有4個小偷
這個例子小偷繼承了被觀察者,當小偷內部數據大於3的時候,就通知觀察各個警察引發重視。由於是參照Java的思想來的,因此看到實現是經過將小偷繼承被觀察者類,警察繼承觀察者類。這個結構其實用java來寫很清晰,觀察者的模式也體現的很清晰,能幫助咱們很好的理解觀察者模式,值得借鑑。比起前端有些寫法在被觀察中存入對應的觀察者,和觀察者的回調,這種寫法其實更分離。優化
3、前端代碼寫觀察者模式this
前端的寫法跟Java裏的實現類是有差異的,看代碼:prototype
/** * 實現一個類 * on():存入被觀察者 * fire():手動觸發某個觀察者,可帶參數 * delete():刪除指定觀察者 * update():被觀察者更新了,執行觀察者回調通知觀察者 * one():某個觀察者只執行一次 * 可鏈式調用 */ function Emiter(){ this.storage = new Map(); } Emiter.prototype.on = function(key,callback){ this.storage.set(key,callback); return this } Emiter.prototype.fire = function(key,data){ this.storage.has(key) ? this.storage.get(key)(data) : console.log('請先註冊對應的事件'); return this } Emiter.prototype.delete = function(key){ this.storage.has(key) ? this.storage.delete(key) : console.log('請先註冊對應的事件'); return this } Emiter.prototype.update = function(data){ for (let [key, value] of this.storage) { value(data); } return this } Emiter.prototype.one = function(key,data){ if(this.storage.has(key)){ this.storage.get(key)(data); this.storage.delete(key); }else{ console.log('請先註冊對應的事件') } return this } //示例 let emiter = new Emiter(); emiter.on('view1',function(data){ console.log('view1收到的數據'+data) }) emiter.on('event',function(){ console.log('emiter') }).on('click',function(){ console.log('click啦') }) emiter.update([1,2,3]) //view1收到的數據1,2,3 emiter click啦
前端拋開一些複雜規範性,能夠直接把觀察者和觀察者的回調保存在被觀察者裏,當被觀察者更新了,執行全部觀察者的回調。這裏之因此有one fire 等方法提供,主要是考慮前端addEventListner也是採用觀察者模式,因此一塊兒提供了。只不過更至關於一對一模式,沒有對應的update,更新全部觀察者的操做。咱們這裏探討的設計模式應該是on update delete爲主線。設計
4、觀察者模式的用途code
觀察者模式主要用於解耦合,一個對象變了,能夠通知多個對象,而不是在回調裏來處理各類狀況。一個場景有個模塊獲取了數據,其餘多個view層都須要用到這個數據。咱們的作法多是會在獲取數據後的模塊回調裏進行各個view層的處理,那若是後續某個模塊的相應業務變了,咱們可能還得回來改這個回調函數。那若是經過觀察者模式,咱們能夠優化爲,每一個模塊徹底分離,當數據回來時告知每一個模塊便可。之後模塊要改變獲取數據後的處理,各個模塊本身去更新。
我如今在想,event對象,是否是內部實現,是在dom改變時傳的參數,而在調用相關事件時能拿到這個回調的參數。
以前看文檔,Vue裏數據變了,如何更新view,用的也是觀察者模式,只不過不是這種實現代碼,後續更新。