什么是編程范式
所謂編程范式(programming paradigm),指的是計算機(jī)編程的基本風(fēng)格或典范模式。我們知道,編程是為了解決問題,而解決問題可以有多種視角和思路,其中普適且行之有效的模式被歸結(jié)為范式。目前來講編程大概有面向過程式(Procedure Oriented Programming)、面向?qū)ο笫?Object 0riented Programming)、函數(shù)式(Functional Programming)、面向切面式(Aspect Oriented Programming)。
編程范式是抽象的,必須通過具體的編程語言來體現(xiàn)。它代表的世界觀往往體現(xiàn)在語言的核心概念中,代表的方法論往往體現(xiàn)在語言的表達(dá)機(jī)制中。反過來說,編程語言的的發(fā)展過程,也代表著編程范式的發(fā)展過程,所以我們從這角度來梳理編程范式的演化過程。
面向過程
我們知道最早的編程語言是機(jī)器語言,我們直接使用機(jī)器指令進(jìn)行編程,這個時候的編程方式是非常繁瑣的,只能解決基本的計算和輸入輸出,基本難以發(fā)展出理論模型。后來發(fā)展出了匯編語言,我們使用助計符來編寫代碼,使用翻譯程序來將代碼翻譯成機(jī)器指令。并且基于這種模式,優(yōu)化出了B語言、C語言,在這個階段我們的主要編程方式,都是過程式編程。即我們的編程的重心,放在了目標(biāo)程序?qū)崿F(xiàn)某些功能的執(zhí)行過程上。在這個階段,我們設(shè)計程序的思路,都是將程序的功能,以計算機(jī)的視角,抽象成輸入輸出等計算任務(wù),來組合實現(xiàn)我們的目標(biāo)功能。
面向?qū)ο?/h3>
在面向過程編程中,我們發(fā)現(xiàn)從程序功能所處理的現(xiàn)實世界的事物、到計算機(jī)能夠處理的計算任務(wù)中,存在著一種生硬的強(qiáng)制的對應(yīng)轉(zhuǎn)換。由于計算機(jī)只能處理格式化的數(shù)據(jù)和計算,導(dǎo)致我們也被迫按照它的方式去思考,這與我們?nèi)祟悓⑹挛锇凑疹悇e和特征來思考的習(xí)慣是不相符的,進(jìn)而增加了我們的程序設(shè)計、實現(xiàn)難度,降低了程序的可讀性和可維護(hù)性。所以我們?yōu)橛嬎銠C(jī)語言增加了新的特性來模擬我們的思維方式,即允許我們以類的方式來組織程序,一個類代表一個現(xiàn)實的事物,它有自己的屬性和行為,以及與其他類的繼承、組合關(guān)系。這種模式就叫面向?qū)ο竽J?,它極大的降低了程序的設(shè)計難度,增加了程序的可讀性和復(fù)用性,為我們構(gòu)建大規(guī)模復(fù)雜的程序提供了更加合理的組織方式。由此特性,基于C語言發(fā)展出了c++語言,再后來又有java語言,到現(xiàn)在,除了少數(shù)的腳本語言之外,絕大部分的語言都支持面向?qū)ο蟮木幊谭绞健?/p>
函數(shù)式編程
函數(shù)式編程這個名詞,在字面上具有一定的迷惑性。因為我們對函數(shù)這個概念并不陌生,它是某個計算過程的組織方式,在所有語言中都存在這種結(jié)構(gòu),雖然有些語言里叫做方法。所以我們看到函數(shù)式編程,很容易就想到C語言這種面向過程的編程方式,然后就會萌生疑問,我們難道不是已經(jīng)用上了函數(shù)式編程了嗎?
實際上我們確實用上了函數(shù)式編程了,這種編程范式里的函數(shù),與我們之前所見的函數(shù)的定義是一樣的,只是它提倡更加極致的使用方式。函數(shù)式編程中,沒有賦值語句,所有的結(jié)果都由計算過程的組合得到,并且函數(shù)的參數(shù),也可以是函數(shù)本身,就像C/C++里的函數(shù)指針一樣。
使用這種范式編程,有幾個主要特點:
1.沒有賦值語句,所有的變量都是不可變的,所已在所有的線程中都是唯一的值,所以它是并發(fā)安全的。但這會導(dǎo)致變量在創(chuàng)建之后,一直存在直到它參與的整個計算過程結(jié)束,從而占用大量的內(nèi)存資源。
2.所有的復(fù)用單元都是函數(shù),這有助于減少程序體積,一定程度上可以提高開發(fā)效率。并且它會使得表達(dá)式的結(jié)構(gòu)更加易于理解。但它也會導(dǎo)致程序設(shè)計的困難,前面我們說了我們思考的自然方式是面向?qū)ο蟮摹?/p>
- 支持惰性計算,即表達(dá)式不在綁定變量時立即求值,而是在需要產(chǎn)生結(jié)果時再進(jìn)行求值。
完全的函數(shù)式編程在目前來說是不流行的,但是我們可以借鑒它的思想。比如在編寫函數(shù)的時候,盡量不修改全局變量和函數(shù)參數(shù),保證函數(shù)的作用的內(nèi)斂性,從而增加程序的健壯性。比如簡化我們的函數(shù)邏輯,編寫小而美的函數(shù),采用函數(shù)嵌套來實現(xiàn)復(fù)雜的功能。比如使用惰性計算,有目的地控制我們程序的計算量分布情況,當(dāng)然這需要語言機(jī)制的支持。目前大部分的語言,都增加了函數(shù)式編程的特性支持,比如java的lambda表達(dá)式,groovy的閉包。
面向切面
在程序中存在很多的通用功能,比如日志記錄,性能統(tǒng)計,安全控制,事務(wù)處理等等,這些功能與程序的業(yè)務(wù)邏輯沒有強(qiáng)制的關(guān)聯(lián)性,屬于輔助或維護(hù)功能,如果我們采用面向?qū)ο蟮姆绞絹韺崿F(xiàn)這些功能,那我們必須在業(yè)務(wù)邏輯實現(xiàn)的同時,處理這些通用的功能。一但這些功能實現(xiàn)需要變更或者擴(kuò)展,會導(dǎo)致業(yè)務(wù)代碼的變更。我們將這些通用的功能,稱為程序的一個切面。
面向切面編程的思想,就是通過預(yù)編譯的方式或者動態(tài)代理技術(shù),在不修改源碼的情況下,為程序增加功能。通過這種方式,分離業(yè)務(wù)邏輯和輔助功能的實現(xiàn),使程序可以專注于業(yè)務(wù)邏輯的實現(xiàn),更加內(nèi)聚和高效。
面向切面編程是很常用的一種技術(shù),它天然是面向?qū)ο缶幊谭绞?,在通用步驟處理能力上的一個補(bǔ)齊,可以極大的簡化程序開發(fā)和提高程序的靈活性。比如java的APT技術(shù)衍生的很多框架,dagger、butterknife、greendao等,使用注解來生成輔助代碼;比如使用ASM技術(shù)直接修改和生成class字節(jié)碼的jacoco,再比如android的databinding框架,甚至是一些hook和插件化機(jī)制,都可以說是AOP編程方式的一種應(yīng)用。