摘要:知識點回顧,上次主要說了函數(shù)式和面向?qū)ο?,命令式和響?yīng)式,系統(tǒng)和系統(tǒng)的差別。以內(nèi)聯(lián)的形式使用。響應(yīng)式中的設(shè)計模式觀察者模式在這種模式中,一個對象維持一系列依賴于它的對象,將有關(guān)的狀態(tài)變更自動的通知給它們。
知識點回顧,上次主要說了函數(shù)式和面向?qū)ο螅钍胶晚憫?yīng)式,push 系統(tǒng)和 pull 系統(tǒng)的差別。在編程范式,風格之外,設(shè)計模式也是在程序設(shè)計中時時刻刻都在使用的東西,今天主要就討論一下設(shè)計模式這個東西。
什么是設(shè)計模式模式是一種可復(fù)用的解決方案,它有三大好處:
模式是已經(jīng)得到驗證的解決方案,因此我們可以在適合的場景中放心的使用它。
模式很容易被復(fù)用,是一種立即可用的解決方案,而且可以對其適當?shù)男薷囊詽M足個性化的需求。
模式富有表達力,它通常有很良好的結(jié)構(gòu)及已經(jīng)設(shè)置好的表達方案的詞匯,可以非常輕松的表達出程序員的意圖。
其實我們每天都在接觸模式,從最簡單的facade(外觀模式,jQuery,lodash為代表)到 singleton,再到MVC,模式可以說無處不再,當然還有rxjs中使用觀察者模式等。有模式,就有反模式,既然模式可以帶來好處,相應(yīng)的反模式就會帶來壞處,在javaScript中,以下就是我們經(jīng)常見到的反模式:
在全局上下文中定義大量的變量來污染全局命名空間。這里的全局我們應(yīng)該以相對的思維考慮,而不是特指window對象。例如:在angularjs 中一個controller 作為封閉的作用域,對于它內(nèi)部定義的各種變量來說,這個作用域就是全局的,寫過angularjs的同學應(yīng)該遇到過,在一個controller中定義很多的變量,然后隨著功能的增加,越來越難以維護。
修改類的原型,尤其是Object類,比修改更過份的是直接替換。
以內(nèi)聯(lián)的形式使用javaScript。
給setTimeout 或 setInterval傳遞字符串而不是函數(shù),這會觸發(fā)內(nèi)部 eval 的執(zhí)行。
響應(yīng)式中的設(shè)計模式 觀察者模式在這種模式中,一個對象維持一系列依賴于它的對象,將有關(guān)的狀態(tài)變更自動的通知給它們。當我們不再希望某個特定的觀察者獲取注冊目標的對象時,它可以從目標的觀察者列表中移除。代碼如下:
觀察者列表類,我們利用這個類來維護觀察者的增刪改查
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(); } } }
主題類,利用這個類來維護一個觀察目標,使用觀察者列表類來維護其自己的觀察者,通過觀察者提供的接口向外發(fā)送目標上發(fā)生的變化。
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); } } }
觀察者類,為目標發(fā)生變化時需要獲得通知的對象提供一個更新接口。
class Observer { constructor() { } update() { // 獲取通知的接口, 不同的observe 可以針對性的設(shè)置更新邏輯 } }
然后我們就可以利用定義好的這些類,實現(xiàn)一些功能,例如,一個主checkbox,當它的狀態(tài)變化時通知頁面上其它的checkbox檢查狀態(tài),代碼大致如下:
HTML代碼
javaScript代碼
const box = document.getElementById("box"); const btn = document.getElementById("button"); const container = document.getElementById("container"); // 工具函數(shù) function extend(source, target) { for (let key in source) { target[key] = source[key]; } } // 利用工具函數(shù)來擴展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); }發(fā)布/訂閱模式
觀察者模式要求希望接收通知的觀察者必須訂閱內(nèi)容改變的事件,而發(fā)布/訂閱模式中添加了一個事件通道,此通道介于訂閱者和發(fā)布者之間,這樣設(shè)置的主要目的是促進發(fā)布者和接收者之間的松散耦合,避免訂閱者和發(fā)布者產(chǎn)和直接的聯(lián)系,如圖:
Observer Pattern
/----<--Subscribe--<-- Subject Observer --->--Fire Event-->--/
Publish/Subscribe Pattern
/----<--Subscribe--<-- Publisher-->--publish-->---Event Channel Subscriber --->---fire event-->--/
在實際的應(yīng)用中, 這兩種模式可以結(jié)合使用,它們都鼓勵開發(fā)者思考應(yīng)用程序之間不同部分之間的關(guān)系,將應(yīng)用程序分解為更小,更松散耦合的塊以提高代碼的復(fù)用。
這兩種模式的優(yōu)缺點優(yōu)點
只需要維護各個對象之間的通信接口的一致性,而無需緊密耦合。
觀察者和目標之間可以建立起一種動態(tài)的關(guān)系,這提供了很大的靈活性,在程序的各部分緊密耦合時,要實現(xiàn)這種動態(tài)關(guān)系是非常不容易的。
缺點
在發(fā)布/訂閱模式中,由于解耦了發(fā)布者和訂閱者,有時會難以保證程序按照我們的預(yù)期進行。例如,發(fā)布者會假設(shè)有人在訂閱它們,當訂閱者發(fā)生錯誤后,由于系統(tǒng)的解耦,發(fā)布者并不會看到這一點。
訂閱者之間非常無視彼此的存在,對于變換發(fā)布者產(chǎn)生的成本視而不見,由于它們之間動態(tài)的關(guān)系,難以跟蹤依賴更新。
rxjs的實現(xiàn)就是建立在這兩種模式的基礎(chǔ)之上,預(yù)先要了解的基本知識通過這兩篇基本上介紹完了,當然都是走馬觀花式的,基中任何一個點拿出來都可以長篇大論,各位如有興趣可以找資料深入研究。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/97264.html
摘要:響應(yīng)式編程是基于異步和事件驅(qū)動的非阻塞程序,只是垂直通過在內(nèi)啟動少量線程擴展,而不是水平通過集群擴展。三特性常用的生產(chǎn)的特性如下響應(yīng)式編程模型適用性內(nèi)嵌容器組件還有對日志消息測試及擴展等支持。 摘要: 原創(chuàng)出處 https://www.bysocket.com 「公眾號:泥瓦匠BYSocket 」歡迎關(guān)注和轉(zhuǎn)載,保留摘要,謝謝! 02:WebFlux 快速入門實踐 文章工程: JDK...
摘要:響應(yīng)式命令式這兩種編程風格的思維方式是完全相反的。第二種方式是工人主動去找工人索取生產(chǎn)手機所要的零件,然后生產(chǎn)一臺完整的手機,這兩種方式就對應(yīng)的響應(yīng)式和命令式。 angular2中內(nèi)置了rxjs,雖然框架本身并沒有強制開發(fā)者使用響應(yīng)式風格來組織代碼,但是從框架開發(fā)團隊的角度可以看出他們必然是認同這種編程風格的。rxjs本質(zhì)是基于函數(shù)式編程的響應(yīng)式風格的庫,函數(shù)式相對于面向?qū)ο髞碚f更加抽...
摘要:那個率先改變的實例的返回值,就會傳遞給的回調(diào)函數(shù)。函數(shù)對函數(shù)的改進,體現(xiàn)在以下四點內(nèi)置執(zhí)行器。進一步說,函數(shù)完全可以看作多個異步操作,包裝成的一個對象,而命令就是內(nèi)部命令的語法糖。中的本質(zhì)就是沒有的隱藏的組件。 1、原型 - jquery使用showImg(https://segmentfault.com/img/bVbwNcY?w=692&h=442);注釋 : 實例雖然不同,但是構(gòu)...
摘要:一般來說,聲明式編程關(guān)注于發(fā)生了啥,而命令式則同時關(guān)注與咋發(fā)生的。聲明式編程可以較好地解決這個問題,剛才提到的比較麻煩的元素選擇這個動作可以交托給框架或者庫區(qū)處理,這樣就能讓開發(fā)者專注于發(fā)生了啥,這里推薦一波與。 本文翻譯自FreeCodeCamp的from-zero-to-front-end-hero-part。 繼續(xù)譯者的廢話,這篇文章是前端攻略-從路人甲到英雄無敵的下半部分,在...
摘要:從這個系列的第一章開始到第五章,基于的響應(yīng)式編程的基礎(chǔ)知識基本上就介紹完了,當然有很多知識點沒有提到,比如,等,不是他們不重要,而是礙于時間精力等原因沒辦法一一詳細介紹。 從這個系列的第一章開始到第五章,基于rxjs的響應(yīng)式編程的基礎(chǔ)知識基本上就介紹完了,當然有很多知識點沒有提到,比如 Scheduler, behaviorSubject,replaySubject等,不是他們不重要,...
閱讀 1199·2023-04-25 17:05
閱讀 3024·2021-11-19 09:40
閱讀 3579·2021-11-18 10:02
閱讀 1752·2021-09-23 11:45
閱讀 3035·2021-08-20 09:36
閱讀 2795·2021-08-13 15:07
閱讀 1145·2019-08-30 15:55
閱讀 2476·2019-08-30 14:11