知識點回顧,上次主要說了函數式和麪向對象,命令式和響應式,push 系統和 pull 系統的差異。在編程範式,風格以外,設計模式也是在程序設計中時時刻刻都在使用的東西,今天主要就討論一下設計模式這個東西。java
模式是一種可複用的解決方案,它有三大好處:程序員
其實咱們天天都在接觸模式,從最簡單的facade(外觀模式,jQuery,lodash爲表明)到 singleton,再到MVC,模式能夠說無處再也不,固然還有rxjs中使用觀察者模式等。有模式,就有反模式,既然模式能夠帶來好處,相應的反模式就會帶來壞處,在javaScript中,如下就是咱們常常見到的反模式:angularjs
在這種模式中,一個對象維持一系列依賴於它的對象,將有關的狀態變動自動的通知給它們。當咱們再也不但願某個特定的觀察者獲取註冊目標的對象時,它能夠從目標的觀察者列表中移除。代碼以下:編程
觀察者列表類,咱們利用這個類來維護觀察者的增刪改查設計模式
class ObserverList { constructor() { }; list = []; add(observer) { this.list.push(observer); } count() { return this.list.length; } get(index) { if(index > -1 && index < this.list.length) { return this.list[index]; }else { return null; } } indexOf(observer, startIndex) { let i = startIndex; let pointer = -1; while( i< this.list.length) { if(this.list[i] === observer) { pointer = i; } i++; } return pointer; } removeIndexAt(index) { if(index === 0) { this.list.shift(); }else if (index === this.list.length - 1) { this.list.pop(); } } }
主題類,利用這個類來維護一個觀察目標,使用觀察者列表類來維護其本身的觀察者,經過觀察者提供的接口向外發送目標上發生的變化。app
class Subject { constructor() { this.observers = new ObserverList(); } addObserver(observer) { this.observers.add(observer); } removeObserver(observer) { this.observers.removeIndexAt(this.observers.indexOf(observer, 0)); } notify(context) { const count = this.observers.count(); for(let i = 0; i< count; i++) { this.observers.get(i).update(context); } } }
觀察者類,爲目標發生變化時須要得到通知的對象提供一個更新接口。函數
class Observer { constructor() { } update() { // 獲取通知的接口, 不一樣的observe 能夠針對性的設置更新邏輯 } }
而後咱們就能夠利用定義好的這些類,實現一些功能,例如,一個主checkbox,當它的狀態變化時通知頁面上其它的checkbox檢查狀態,代碼大體以下:工具
HTML代碼this
<button id="button">Add Observer</button> <input id="box" type="checkbox"> <div id="container"></div>
javaScript代碼spa
const box = document.getElementById('box'); const btn = document.getElementById('button'); const container = document.getElementById('container'); // 工具函數 function extend(source, target) { for (let key in source) { target[key] = source[key]; } } // 利用工具函數來擴展DOM元素 extend(new Subject(), box); // 將點擊事件通知給觀察者 box.onclick = function { box.notify(box.checked); } btn.onclick = function addNewObserver() { const check = document.createElement('input'); check.type = 'checkbox'; extend(new Observer(), check); // 重寫自定義的更新行爲 check.update = (value) => this.checked = value; // 爲subject的觀察者列表中添加新的觀察者 box.addObserver(check); // 將觀察者附加到容器上 container.appendChild(check); }
觀察者模式要求但願接收通知的觀察者必須訂閱內容改變的事件,而發佈/訂閱模式中添加了一個事件通道,此通道介於訂閱者和發佈者之間,這樣設置的主要目的是促進發布者和接收者之間的鬆散耦合,避免訂閱者和發佈者產和直接的聯繫,如圖:
Observer Pattern
/----<--Subscribe--<--\ Subject Observer \--->--Fire Event-->--/
Publish/Subscribe Pattern
/----<--Subscribe--<--\ Publisher-->--publish-->---Event Channel Subscriber \--->---fire event-->--/
在實際的應用中, 這兩種模式能夠結合使用,它們都鼓勵開發者思考應用程序之間不一樣部分之間的關係,將應用程序分解爲更小,更鬆散耦合的塊以提升代碼的複用。
優勢
缺點
rxjs的實現就是創建在這兩種模式的基礎之上,預先要了解的基本知識經過這兩篇基本上介紹完了,固然都是蜻蜓點水式的,基中任何一個點拿出來均可以長篇大論,各位若有興趣能夠找資料深刻研究。