常用編程范式
大概有四種敞嗡,如果按照類似繼承圖譜來看的話结借,應(yīng)該如下圖:
函數(shù)式編程(Functional Program,FP)
函數(shù)式編程是使用函數(shù)來編程的一種
編程范式
無副作用
實際上函數(shù)編程需要可觀測的作用贞盯,例如把結(jié)果顯示在屏幕上。換句話說與外界的交互不會發(fā)生在計算過程中婿滓,而是發(fā)生在計算完成后
——將會推遲副作用并單獨應(yīng)用
函數(shù)式編程就是編寫非有意副作用的程序邻薯,如果需要副作用盡可能的延遲副作用發(fā)生的時機。如果既有返回值又有副作用御滩,這種程序就不是函數(shù)式鸥拧。
引用透明
函數(shù)式程序的輸出只能取決于自己的參數(shù),這就意味著函數(shù)式代碼不能從控制臺削解、文件等讀取數(shù)據(jù)富弦,既函數(shù)式代碼是引用透明的(不被外界影響到的代碼是引用透明的)。
引用透明代碼的特點:
- 它是獨立的钠绍。不依賴與任何外部設(shè)備舆声,可以在任何上下文中使用它——只需要提供一個有效的參數(shù)。
- 它是確定的柳爽。在引用透明的代碼中媳握,不會有意外發(fā)生,結(jié)果可能是錯誤的磷脯,但是一個參數(shù)對應(yīng)的結(jié)果肯定是相同的蛾找。
- 它絕對不會拋出任何的Exception。但是它可能會拋出錯誤(不是異常)——拋出error赵誓。例如OOME或者SOE打毛,這些表示代碼有bug,并不是作為程序員的你或是你api的用戶應(yīng)該處理的——當(dāng)然修復(fù)這個bug肯定是你要做的俩功。
- 任何時候它都不會導(dǎo)致其他代碼意外失敗幻枉。例如他不會改變參數(shù)或者外界數(shù)據(jù),從而導(dǎo)致調(diào)用者發(fā)現(xiàn)自己的數(shù)據(jù)過期或者并發(fā)訪問異常诡蜓。
- 它不會由于外部設(shè)備(數(shù)據(jù)庫熬甫、文件系統(tǒng))不可用、太慢或壞掉而崩潰——但是你的程序會蔓罚。
優(yōu)勢
- 函數(shù)式程序更加易于推斷椿肩,因為他們有確定性瞻颂。確定的輸入會有確定的輸出,在許多情況下可以證明程序是正確的郑象,而不是在大量測試后仍然無法確定程序是否會在意外情況下出錯贡这。
- 函數(shù)式程序更加易于測試。沒有副作用厂榛,所以不需要那些經(jīng)常用于在測試?yán)锔綦x程序及外界的mock盖矫。
- 函數(shù)式程序更加模塊化,只關(guān)心輸入和輸出噪沙,不用去處理異常炼彪,處理副作用,不用關(guān)心上下文變化正歼,并發(fā)等。
- 函數(shù)式編程讓符合和重新符合更加簡單拷橘。基礎(chǔ)函數(shù)組成高級別函數(shù)局义,因為要用骨頭嗎,所以無須修改就可以為其他程序所重用——例如編寫了一個求和函數(shù)冗疮,A程序可以用萄唇,B程序也可以用。
- 函數(shù)式程序總是線程安全的术幔,因為防止了共享狀態(tài)的變化另萤。并不意外這所有數(shù)據(jù)都不需要改變,只有共享數(shù)據(jù)才需要诅挑。
響應(yīng)式編程(Reactive Programming:RP)
響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的
編程范式
這意味著可以在編程語言中很方便地表達靜態(tài)或動態(tài)的數(shù)據(jù)流四敞,而相關(guān)的計算模型會自動將變化的值通過數(shù)據(jù)流進行傳播。
響應(yīng)式編程最初是為了簡化交互式用戶界面的創(chuàng)建和實時系統(tǒng)動畫的繪制而提出來的一種方法拔妥,但它本質(zhì)上是一種通用的編程范式忿危。
以程序開發(fā)過程為例,
程序接收輸入產(chǎn)生輸出没龙。輸出就是對輸入做了一些事的結(jié)果铺厨。輸入,轉(zhuǎn)換硬纤,輸出解滓,完成。
輸入是應(yīng)用動作的全部來源筝家。點擊洼裤、鍵盤事件、定時器事件肛鹏、GPS時間逸邦、網(wǎng)絡(luò)請求響應(yīng)都算是輸入恩沛。這些事件被傳遞到應(yīng)用中,應(yīng)用將他們以某種方式混合缕减,產(chǎn)生了結(jié)果:就是輸出雷客。
輸出通常會改變應(yīng)用的UI。開關(guān)狀態(tài)變化桥狡、列表有了新的元素都是UI變化搅裙。也有可能讓磁盤上某個文件產(chǎn)生變化,或者產(chǎn)生一個API請求裹芝,這都是應(yīng)用的輸出部逮。
應(yīng)用的輸入輸出可以產(chǎn)生很多次。
應(yīng)用打開后嫂易,不只是一個簡單的 輸入→工作→輸出 就構(gòu)成了一個生命周期兄朋。應(yīng)用經(jīng)常有大量的輸入并基于這些輸入產(chǎn)生輸出。
- 響應(yīng)式編程是一種和
事件流
有關(guān)的編程模式怜械,關(guān)注導(dǎo)致狀態(tài)值改變的行為事件颅和,一系列事件組成了事件流。- 一系列事件是導(dǎo)致屬性值發(fā)生變化的原因缕允。FRP非常
類似于設(shè)計模式里的觀察者模式
峡扩。- RP與普通的函數(shù)式編程相似,但是每個函數(shù)可以接收一個輸入值的流障本,如果其中教届,一個新的輸入值到達的話,這個函數(shù)將根據(jù)最新的輸入值重新計算驾霜,并且產(chǎn)生一個新的輸出案训。這是一種”數(shù)據(jù)流”編程模式。
為什么用響應(yīng)式?
- 開發(fā)過程中寄悯,狀態(tài)以及狀態(tài)之間依賴過多萤衰,RAC更加有效率地處理事件流,而無需顯式去管理狀態(tài)猜旬。在OO或者過程式編程中脆栋,狀態(tài)變化是最難跟蹤,最頭痛的事洒擦。這個也是最重要的一點椿争。
- 減少變量的使用,由于它跟蹤狀態(tài)和值的變化熟嫩,因此不需要再申明變量不斷地觀察狀態(tài)和更新值秦踪。
- 提供統(tǒng)一的消息傳遞機制,將oc中的通知,action椅邓,KVO以及其它所有UIControl事件的變化都進行監(jiān)控柠逞,當(dāng)變化發(fā)生時,就會傳遞事件和值景馁。
- 當(dāng)值隨著事件變換時板壮,可以使用map,filter合住,reduce等函數(shù)便利地對值進行變換操作绰精。
函數(shù)響應(yīng)式編程(Functional Reactive Programming:FRP)
響應(yīng)式編程思想為體, 函數(shù)式編程思想為用
可以結(jié)合ReactiveCocoa(簡稱RAC)
來理解,
RAC
結(jié)合了幾種編程風(fēng)格:
函數(shù)式編程(Functional Programming):使用高階函數(shù)透葛。比如函數(shù)用其它函數(shù)作為參數(shù)笨使。
響應(yīng)式編程(Reactive Programming):關(guān)注于數(shù)據(jù)流和變化傳播。
所以僚害,你可能聽說過ReactiveCocoa
被描寫敘述為函數(shù)響應(yīng)式編程(FRP)
框架硫椰。
有句比喻非常好非常形象的對RAC
做了總結(jié):
“能夠把信號想象成水龍頭,僅僅只是里面不是水贡珊,而是玻璃球(value)最爬,直徑跟水管的內(nèi)徑一樣,這樣就能保證玻璃球是依次排列门岔。不會出現(xiàn)并排的情況(數(shù)據(jù)都是線性處理的,不會出現(xiàn)并發(fā)情況)烤送。水龍頭的開關(guān)默認(rèn)是關(guān)的寒随。除非有了接收方(subscriber),才會打開帮坚。
這樣僅僅要有新的玻璃球進來妻往,就會自己主動傳送給接收方。
能夠在水龍頭上加一個過濾嘴(filter)试和。不符合的不讓通過讯泣,也能夠加一個修改裝置,把球改變成符合自己的需求(map)阅悍。
也能夠把多個水龍頭合并成一個新的水龍頭(combineLatest:reduce:)好渠,這樣僅僅要當(dāng)中的一個水龍頭有玻璃球出來,這個新合并的水龍頭就會得到這個球节视。”
RXSwift
RxSwift 是 ReactiveX 針對Swift 的實現(xiàn)拳锚。
RxSwift是一個針對于Swift語言的響應(yīng)式編程框架,旨在使異步操作和事件/數(shù)據(jù)流的實現(xiàn)變的簡單寻行。
Observables 和 Observers
兩個基本概念:Observable和Observer霍掺。
- Observable是發(fā)出變化通知的對象。
- Observer是監(jiān)聽Observable的對象。當(dāng)Observable變化時杆烁,Observer會收到通知牙丽。
可以有多個Observer監(jiān)聽同一個Observable。當(dāng)Observable發(fā)生變化時兔魂,會通知它所有的Observer烤芦。
DisposeBag
DisposeBag是用來處理 ARC 和內(nèi)存管理的。 DisposeBag是Observer 對象的一個虛擬包入热,當(dāng)Observer的父對象被釋放時拍棕,這個虛擬包會被丟棄。
當(dāng)帶有DisposeBag屬性的對象的 deinit()方法被調(diào)用時勺良,DisposeBag會清空绰播,并且每一個用完即丟棄(disposable)的Observer 會自動取消對觀察內(nèi)容的監(jiān)聽。這可以讓 ARC 正常的回收內(nèi)存尚困。
如果沒有DisposeBag蠢箩,會有兩種后果:要么Observer會產(chǎn)生一個 retain cycle,將無限期的進行監(jiān)聽事甜;要么Observer被意外釋放谬泌,導(dǎo)致程序崩潰。
所以在設(shè)置Observable對象時逻谦,將其添加到DisposeBag中掌实。
核心邏輯
可以參考我的博客RXSwift-核心邏輯,RXSwift
正式基于這樣的核心邏輯才實現(xiàn)函數(shù)響應(yīng)式編程邦马。