丨函數(shù)式編程之不變性怎樣保證我的代碼不會(huì)被別人破壞_第1頁(yè)
丨函數(shù)式編程之不變性怎樣保證我的代碼不會(huì)被別人破壞_第2頁(yè)
丨函數(shù)式編程之不變性怎樣保證我的代碼不會(huì)被別人破壞_第3頁(yè)
丨函數(shù)式編程之不變性怎樣保證我的代碼不會(huì)被別人破壞_第4頁(yè)
丨函數(shù)式編程之不變性怎樣保證我的代碼不會(huì)被別人破壞_第5頁(yè)
已閱讀5頁(yè),還剩4頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

這個(gè)程序庫(kù)是其他人封裝的,拿過(guò)來(lái)用。按理說(shuō),我調(diào)用的這個(gè)函數(shù)邏輯也不是特別復(fù)雜,不應(yīng)該出現(xiàn)什么問(wèn)題。不過(guò),為了更快定位問(wèn)題,我還是打開(kāi)了這個(gè)程序庫(kù)的源代碼。經(jīng)過(guò)一番挖掘,我發(fā)現(xiàn)在這個(gè)函數(shù)底層實(shí)現(xiàn)中,出現(xiàn)了一個(gè)全局變量。分析之后,我發(fā)現(xiàn)正是這個(gè)全局變量引起了這場(chǎng)麻煩,因?yàn)樵谖业拇a執(zhí)行過(guò)程中,有別的程序會(huì)調(diào)用另外的函數(shù),修改這個(gè)全局變量的值,最終,導(dǎo)致了我的程序執(zhí)行失敗。從表面上看,我調(diào)用的這個(gè)函數(shù)和另外那個(gè)函數(shù)八竿子都打不到,但是,它們卻通過(guò)一個(gè)底層的全局變量,產(chǎn)生了相互的影響。這就是一類非常讓人頭疼的Bug。有人認(rèn)為這是全局變量使用不當(dāng)造成的,在Jaa中,甚至取消了全局變量,但類似的問(wèn)題并沒(méi)有因此減少,只是以不同面貌展現(xiàn)出來(lái)而已,比如,saic變量。那么造成這類問(wèn)題的真正原因是什么呢?真正原因就在于變量是可變的代代12345678classSample1privatestaticfinalDateFormatformatnewpublicString{returnformat.format(new}}如果你不熟悉JDKSimpleDateFormat,你可能會(huì)覺(jué)得這段代碼看上去還不錯(cuò)。然而,publicclassSample2publicStringgetCurrentDateText()DateFormatformat=newreturnformat.format(new556}兩段代碼最大的區(qū)別就在于,SimpleDateFormat哪里構(gòu)建。一個(gè)是被當(dāng)作了一個(gè)字SimpleDateFormat對(duì)象是否共享。為什么這個(gè)對(duì)象共享會(huì)有問(wèn)題呢?翻看format方法的源碼,你會(huì)發(fā)現(xiàn)這樣1這里的calendarSimpleDateFormat個(gè)類的一個(gè)字段,正是因?yàn)樵趂ormat程中修改了calendar字段,所以,它才會(huì)出問(wèn)題。我們來(lái)看看這種問(wèn)題是怎么出現(xiàn)的,就像下面這張圖看到A線程把變量的值修改成自己需要的這時(shí)發(fā)生線程切換,B線程開(kāi)始執(zhí)行,將變量的值修改成它所需要的線程切換回來(lái),A程繼續(xù)執(zhí)行,但此時(shí)變量已經(jīng)不是自己設(shè)置的值了,所以,執(zhí)行會(huì)回到SimpleDateFormat上,問(wèn)題是一樣的,calendar就是那個(gè)共享的變量。一個(gè)線程剛剛設(shè)置的值,可能會(huì)被另外一個(gè)線程修改掉,因此會(huì)造成結(jié)果的不正確。而在Sample2的寫(xiě)法中,通過(guò)每次創(chuàng)建一個(gè)新的SimpleDateFormat對(duì)象,二者之間的共享解那如果我還是想按照Sample1的寫(xiě)法寫(xiě),SimpleDateFormat這個(gè)庫(kù)應(yīng)該怎么改寫(xiě)呢?可能你會(huì)想,SimpleDateFormat的作者沒(méi)寫(xiě)好,如果換我寫(xiě),我就會(huì)給它加上一(synchronized)或者加上鎖(Lock)。你甚至都沒(méi)有注意,你輕易地將多線程的復(fù)雜性引入了進(jìn)來(lái)。還記得我在分離關(guān)注點(diǎn)那節(jié)討論的問(wèn)題嗎,多線程是另外一個(gè)關(guān)注點(diǎn),能少用,盡量少用。一個(gè)更好的辦法是將alenar變成局部變量,這樣一來(lái),不同線程之間共享變量的問(wèn)題就得到了根本的解決。但是,這類非常頭疼的問(wèn)題在函數(shù)式編程中卻幾乎不存在,這就依賴于函數(shù)式編程的不變性。函數(shù)式編程的不變性主要體現(xiàn)在值和純函數(shù)上。值,你可以將它理解為一個(gè)初始化之后就不再改變的量,換句話說(shuō),當(dāng)你使用一個(gè)值的時(shí)候,值是不會(huì)變的。純函數(shù),是符合下面兩點(diǎn)的函數(shù):把值和純函數(shù)合起來(lái)看,值保證不會(huì)顯式改變一個(gè)量,而純函數(shù)保證的是,不會(huì)隱式改變一個(gè)量。我們,函數(shù)式編程中的函數(shù)源自數(shù)學(xué)中的函數(shù)。在這個(gè)語(yǔ)境里,函數(shù)就是純函數(shù),一個(gè)函數(shù)計(jì)算之后是不會(huì)產(chǎn)生額外的改變的,而函數(shù)中用到的一個(gè)一個(gè)量就是值,它們是不會(huì)隨著計(jì)算改變的。所以,在函數(shù)式編程中,計(jì)算天然就是不變的。正是由于不變性的存在,我們面遇到的那些問(wèn)題也就不再是問(wèn)題了。一方面,如果你拿到一個(gè)量,這次的值是1,下一次它還是1,我們完全不用擔(dān)心它會(huì)改變。另一方面,我們調(diào)用一個(gè)函數(shù),傳進(jìn)去同樣的參數(shù),它保證給出同樣的結(jié)果,行為是完全可以預(yù)期的,不會(huì)碰觸到其他部分。即便是在多線程的情況下,我們也不必考慮同步的問(wèn)題,后續(xù)一系列的問(wèn)題也就不存在了。這與我們習(xí)慣的方式有著非常大的區(qū)別,因?yàn)閭鹘y(tǒng)方式的基礎(chǔ)是面向內(nèi)存單元的,改來(lái)改去甚至已經(jīng)成為了程序員的本能。所以,我們對(duì)outer=couer+1這種代碼習(xí)以為常,而初學(xué)編程的人總會(huì)覺(jué)得這在數(shù)學(xué)上是不成立的。在之前的討論中,我們,傳統(tǒng)的編程方式占優(yōu)的地方是執(zhí)行效率,而現(xiàn)如今,這個(gè)優(yōu)點(diǎn)則越來(lái)越不明顯,反而是因?yàn)榈教幙勺兌鴰?lái)了的問(wèn)題。相較之下,我們更應(yīng)該在現(xiàn)在的設(shè)計(jì)中,考慮借鑒函數(shù)式編程的思路,把不變性地應(yīng)用在我們的代碼之中。那怎么應(yīng)用呢?首先是值。我們可以編寫(xiě)不變類,就是對(duì)象一旦構(gòu)造出來(lái)就不能改變Java程序員最熟悉的不變類應(yīng)該就是String類,怎樣編寫(xiě)不變類呢如果需要有改變,返回一個(gè)新的對(duì)象,而不是修改已有字前面兩點(diǎn)可能還好理解,最后一點(diǎn),我們可以看一下JavaString類的rece方法簽1String ce(charoldChar,char在這里,我們會(huì)用一個(gè)新的字符(newChar)替換掉這個(gè)字符串中原有的回。這樣一來(lái),使用原來(lái)這個(gè)字符串的類并不用擔(dān)心自己的內(nèi)容會(huì)隨之變化。我們?cè)賮?lái)看純函數(shù)。編寫(xiě)純函數(shù)的重點(diǎn)是,不修改任何字段,也不調(diào)用修改字段內(nèi)容的方法。因?yàn)樵趯?shí)際的工作中,我們使用的大多數(shù)都是傳統(tǒng)的程序設(shè)計(jì)語(yǔ)言,而不是嚴(yán)格的函數(shù)式編程語(yǔ)言,不是所有用到的量都是值。所以,站在實(shí)用性的角度,如果要使用變量,就使用局部變量。還有一個(gè)實(shí)用性的編程建議,就是使用語(yǔ)法中不變的修飾符,比如,Java就盡可能多使用final,C/C++就多寫(xiě)const。無(wú)論是修飾變量還是方法,它們的主要作用就是讓編譯器提當(dāng)你有了用不變性思考問(wèn)題的角度,你會(huì)發(fā)現(xiàn)之前的很多編程習(xí)慣是極其糟糕的Java程序員最喜歡寫(xiě)的setter,它就是提供了一個(gè)接口,修改一個(gè)對(duì)象內(nèi)部的值不過(guò),純粹的函數(shù)式編程是很的,我們只能把編程原則設(shè)定為盡可能編寫(xiě)不變類和純函數(shù)。但僅僅是這么來(lái)看,你也會(huì)發(fā)現(xiàn),自己從前寫(xiě)的很多代碼,尤其是大量負(fù)責(zé)業(yè)務(wù)邏而正是不變性的優(yōu)勢(shì),有些新的程序設(shè)計(jì)語(yǔ)言默認(rèn)選項(xiàng)不再是變量,而是值。比如,Rust里,你這么的是一個(gè)值,因?yàn)橐坏┏跏蓟耍銓o(wú)法修改它1letresult=而如果你想一個(gè)變量,必須顯式地告訴編譯器1letmutresult=Java一個(gè)專門(mén)的Valhalla項(xiàng)目就是做這個(gè)的。你也看現(xiàn)在回過(guò)頭來(lái)看編程范式那一講里說(shuō)的約函數(shù)式編程,限制使用賦值語(yǔ)句,它是對(duì)程序中的賦值施加了約然而,這類問(wèn)題在函數(shù)式編程中并不存在。其中,重要的原因就是函數(shù)式編程的不變性。函數(shù)式編程的不變性主要體現(xiàn)在它的值和純函數(shù)上。深入學(xué)習(xí)函數(shù)式編程時(shí),你會(huì)遇到的與之相關(guān)的各種說(shuō)法:無(wú)副作用、無(wú)狀態(tài)、透明等等,其實(shí)都是在討論不變性。即便使用傳統(tǒng)的程序設(shè)計(jì)語(yǔ)言,我們也可以從中借鑒一些編程的方法。比如,編寫(xiě)不變經(jīng)過(guò)了這三講的介紹,相信你已經(jīng)對(duì)函數(shù)式編程有了很多認(rèn)識(shí),不過(guò),把設(shè)計(jì)中最常用的部分給你做了一個(gè)介紹,這遠(yuǎn)遠(yuǎn)不是函數(shù)式編程的全部。就算Jaa這種后期增補(bǔ)的函數(shù)式編程的語(yǔ)言,其中也包含了惰性求值、Opioal等諸多內(nèi)容,值得你去深入了解。不過(guò)我相信有了前面知識(shí)的鋪墊,你再去學(xué)習(xí)函數(shù)式編程其他相關(guān)內(nèi)容,難度系數(shù)就會(huì)降低一些。如果今天的內(nèi)容你只能記住一件事,那請(qǐng)記?。罕M量編寫(xiě)不變類和純函最后,請(qǐng)你去了解一下Event Sourcing,結(jié)合今天的內(nèi)容,談?wù)勀銓?duì)它的理解。感謝閱讀,如果你覺(jué)得這一講的內(nèi)容對(duì)你

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論