中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

整潔代碼之道——重構(gòu)

2018-07-20    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

寫在前面

現(xiàn)在的軟件系統(tǒng)開發(fā)難度主要在于其復(fù)雜度和規(guī)模,客戶需求也不再像Winston Royce瀑布模型期望那樣在系統(tǒng)編碼前完成所有的設(shè)計(jì)滿足用戶軟件需求。在這個(gè)信息爆炸技術(shù)日新月異的時(shí)代,需求總是在不斷的變化,隨之在2001年業(yè)界17位大牛聚集在美國(guó)猶他州的滑雪勝地雪鳥(Snowbird)雪場(chǎng),提出了“Agile”(敏捷)軟件開發(fā)價(jià)值觀,并在他們的努力推動(dòng)下,開始在業(yè)界流行起來(lái)。在《代碼整潔之道》一書中提出:一種軟件質(zhì)量,可持續(xù)開發(fā)不僅在于項(xiàng)目架構(gòu)設(shè)計(jì),還與代碼質(zhì)量密切相關(guān),代碼的整潔度和質(zhì)量成正比,一份整潔的代碼在質(zhì)量上是可靠的,為團(tuán)隊(duì)開發(fā),后期維護(hù),重構(gòu)奠定了良好的基礎(chǔ)。

接下來(lái)筆者將結(jié)合自己之前的重構(gòu)實(shí)踐經(jīng)驗(yàn),來(lái)探討平時(shí)實(shí)際開發(fā)過(guò)程中我們注重代碼優(yōu)化實(shí)踐細(xì)節(jié)之道,而不是站在純空洞的理論來(lái)談?wù)摯a整潔之道。

在具體探討如何進(jìn)行代碼優(yōu)化之前,我們首先需要去探討和明確下何謂是“代碼的壞味道”,何謂是“整潔優(yōu)秀代碼”。因?yàn)橐磺袃?yōu)化的根源都是來(lái)自于我們平時(shí)開發(fā)過(guò)程中而且是開發(fā)人員自己產(chǎn)生的“代碼壞味道”。

代碼的壞味道

“如果尿布臭了,就換掉它!保Z(yǔ)出Beck奶奶,論撫養(yǎng)小孩的哲學(xué)。同樣,代碼如果有壞味道了,那么我們就需要去重構(gòu)它使其成為優(yōu)秀的整潔代碼。

談?wù)摰胶沃^代碼的壞味道,重復(fù)代碼(Duplicated Code)首當(dāng)其沖。重復(fù)在軟件系統(tǒng)是萬(wàn)惡的,我們熟悉的分離關(guān)注點(diǎn),面向?qū)ο笤O(shè)計(jì)原則等都是為了減少重復(fù)提高重用,Don’t repeat yourself(DRY)。關(guān)于DRY原則,我們?cè)谄綍r(shí)開發(fā)過(guò)程中必須要嚴(yán)格遵守。

其次還有其他壞味道:過(guò)長(zhǎng)函數(shù)(Long Method)、過(guò)大的類(Large Class)、過(guò)長(zhǎng)參數(shù)列表(Long Parameter List)、冗余類(Lazy Class)、冗余函數(shù)(Lazy Function)無(wú)用函數(shù)參數(shù)(Unused Function Parameter)、函數(shù)圈復(fù)雜度超過(guò)10(The Complexity is over 10)、依戀情結(jié)(Feature Envy)、Switch過(guò)多使用(Switch Abuse)、過(guò)度擴(kuò)展設(shè)計(jì)(Over-extend design)、不可讀或者可讀性差的變量名和函數(shù)名(unread variable or function name)、異曲同工類(Alternative Classes with Different Interfaces)、過(guò)度耦合的消息鏈(Message Chains)、令人迷惑的臨時(shí)字段(Temporary Field)、過(guò)多注釋(Too Many Comments)等壞味道。

整潔代碼

什么是整潔代碼?不同的人會(huì)站在不同的角度闡述不同的說(shuō)法。而我最喜歡的是Grady Booch(《面向?qū)ο蠓治雠c設(shè)計(jì)》作者)闡述:

“整潔的代碼簡(jiǎn)單直接。整潔的代碼如同優(yōu)美的散文。整潔的代碼從不隱藏設(shè)計(jì)者的意圖,充滿了干凈利落的抽象和直截了當(dāng)?shù)目刂普Z(yǔ)句!

整潔的代碼就是一種簡(jiǎn)約(簡(jiǎn)單而不過(guò)于太簡(jiǎn)單)的設(shè)計(jì),閱讀代碼的人能很清晰的明白這里在干什么,而不是隱澀難懂,整潔的代碼讀起來(lái)讓人感覺到就像閱讀散文-藝術(shù)的沉淀,作者是精心在意締造出來(lái)。

整潔代碼是相對(duì)于代碼壞味道的,如何將壞味道代碼優(yōu)化成整潔代碼,正是筆者本文所探討的重點(diǎn)內(nèi)容:整潔代碼之道-重構(gòu),接下來(lái)筆者將從幾個(gè)角度重點(diǎn)描述如何對(duì)軟件進(jìn)行有效有技巧的重構(gòu)。

重構(gòu) — Why

在軟件開發(fā)過(guò)程中往往開發(fā)者不經(jīng)意間就能產(chǎn)生代碼的壞味道,特別是團(tuán)隊(duì)人員水平參差不齊每個(gè)人的經(jīng)驗(yàn)和技術(shù)能力不同的情況下更容易產(chǎn)生不同階段的代碼壞味道。并且隨著需求的迭代和時(shí)間推移,代碼的壞味道越來(lái)越嚴(yán)重,甚至影響到團(tuán)隊(duì)的開發(fā)效率,那么遇到這個(gè)問(wèn)題該如何去解決。

在軟件開發(fā)Coding之前我們不可能事先了解所有的需求,軟件設(shè)計(jì)肯定會(huì)有考慮不周到不全面的地方,而且隨著項(xiàng)目需求的Change,很有可能原來(lái)的代碼設(shè)計(jì)結(jié)構(gòu)已經(jīng)不能滿足當(dāng)前需求。

更何況,我們很少有機(jī)會(huì)從頭到尾參與并且最終完成一個(gè)項(xiàng)目,基本上都是接手別人的代碼,即使這個(gè)項(xiàng)目是從頭參與的,也有可能接手團(tuán)隊(duì)其他成員的代碼。我們都有過(guò)這樣的類似的抱怨經(jīng)歷,看到別人的代碼時(shí)感覺就像垃圾一樣特別差勁,有一種強(qiáng)烈的完全想重寫的沖動(dòng),但一定要壓制住這種沖動(dòng),你完全重寫,可能比原來(lái)的好一點(diǎn),但浪費(fèi)時(shí)間不說(shuō),還有可能引入原來(lái)不存在的Bug,而且,你不一定比原來(lái)設(shè)計(jì)得好,也許原來(lái)的設(shè)計(jì)考慮到了一些你沒考慮到的分支或者異常情況。

我們寫的代碼,終有一天也會(huì)被別人接手,很可能到時(shí)別人會(huì)有和我們現(xiàn)在一樣的沖動(dòng),所以開發(fā)者在看別人代碼時(shí)候,要懷著一顆學(xué)習(xí)和敬畏之心,去發(fā)現(xiàn)別人的代碼之美,在這個(gè)過(guò)程中挑出寫的比較好的優(yōu)秀代碼,吸取精華,去其糟粕,在這個(gè)基礎(chǔ)上,我們?cè)偃フ勚貥?gòu),那么你的重構(gòu)會(huì)是一個(gè)好的開端。

總之,我們要做的是重構(gòu)不是重寫,要先從小范圍的局部重構(gòu)開始,然后逐步擴(kuò)展到整個(gè)模塊。

重構(gòu) — 作用

重構(gòu),絕對(duì)是軟件開發(fā)寫程序過(guò)程中最重要的事之一。那么什么是重構(gòu),如何解釋重構(gòu)。名詞:對(duì)軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。 動(dòng)詞 :使用一系列重構(gòu)手法,在不改變軟件可觀察行為的前提下,調(diào)整其結(jié)構(gòu)。

重構(gòu)不只可以改善既有的設(shè)計(jì)結(jié)構(gòu),還可以幫助我們理解原來(lái)很難理解的流程。比如一個(gè)復(fù)雜的條件表達(dá)式,我們可能需要很久才能看明白這個(gè)表達(dá)式的作用,還可能看了好久終于看明白了,過(guò)了沒多長(zhǎng)時(shí)間又忘了,現(xiàn)在還要從頭看,如果我們把這個(gè)表達(dá)式運(yùn)用Extract Method抽象出來(lái),并起一個(gè)易于理解的名字,如果函數(shù)名字起得好,下次當(dāng)我們?cè)倏吹竭@段代碼時(shí),不用看邏輯我們就知道這個(gè)函數(shù)是做什么的。

如果對(duì)這個(gè)函數(shù)內(nèi)所有難于理解的地方我們做了適當(dāng)?shù)闹貥?gòu),把每個(gè)細(xì)小的邏輯抽象成一個(gè)小函數(shù)并起一個(gè)容易理解的名字,當(dāng)我們看代碼時(shí)就有可能像看注釋一樣,不用再像以前一樣通過(guò)看代碼的實(shí)現(xiàn)來(lái)猜測(cè)這段代碼到底是做什么的,我一直堅(jiān)持和秉持這個(gè)觀點(diǎn):好的代碼勝過(guò)注釋,畢竟注釋還是有可能更新不及時(shí)的,不及時(shí)最新的注釋容易更其他人帶來(lái)更多的理解上的困惑。

此外重構(gòu)可以使我們?cè)黾訉?duì)代碼和業(yè)務(wù)邏輯功能的理解,從而幫助我們找到Bug;重構(gòu)可以幫助我們提高編程速度,即重構(gòu)改善了程序結(jié)構(gòu)設(shè)計(jì),并且因?yàn)橹貥?gòu)的可擴(kuò)展性使添加新功能變得更快更容易。

重構(gòu) — 時(shí)機(jī)

理解了重構(gòu)的意義和作用,那么我們何時(shí)開始重構(gòu)呢?筆者一直堅(jiān)持這種觀點(diǎn):重構(gòu)是一個(gè)持續(xù)的系統(tǒng)性的工程,它是貫穿于整個(gè)軟件開發(fā)過(guò)程中,我們無(wú)需專門的挑出時(shí)間進(jìn)行重構(gòu),重構(gòu)應(yīng)該隨時(shí)隨地的進(jìn)行,即遵循三次法則:事不過(guò)三,三則重構(gòu)。這個(gè)準(zhǔn)則表達(dá)的意思是:第一次去實(shí)現(xiàn)一個(gè)功能盡管去做,但是第二次做類似的功能設(shè)計(jì)時(shí)會(huì)產(chǎn)生反感,但是還是會(huì)去做,第三次還是實(shí)現(xiàn)類似的功能做同樣的事情,那你就應(yīng)該去重構(gòu)。三次準(zhǔn)則比較抽象,那么對(duì)應(yīng)到我們具體的軟件開發(fā)流程中,一般可以在這三個(gè)時(shí)機(jī)去進(jìn)行:

(1) 當(dāng)添加新功能時(shí)如果不是特別容易,可以通過(guò)重構(gòu)使添加特性和新功能變得更容易。在添加新功能的時(shí)候,我們就先清理這個(gè)功能所需要的代碼;ㄒ稽c(diǎn)時(shí)間,用滴水穿石的方法逐漸清理代碼,隨著時(shí)間的推移,我們的代碼就會(huì)越來(lái)越干凈,開發(fā)速度也會(huì)越來(lái)越快。

(2) 修改Bug的時(shí)候去重構(gòu),比如你在查找定位Bug的過(guò)程中,發(fā)現(xiàn)以前自己的代碼或者別人的代碼因?yàn)樵O(shè)計(jì)缺陷比如可擴(kuò)展性、健壯性比較差造成的,那么此時(shí)就是一個(gè)比較好的重構(gòu)時(shí)機(jī)?赡苓@個(gè)時(shí)候很多同學(xué)就有疑問(wèn)了,認(rèn)為我開發(fā)要趕進(jìn)度,沒有時(shí)間去重構(gòu),或者認(rèn)為我打過(guò)補(bǔ)丁把Bug解決不就行了,不需要去重構(gòu)。根據(jù)筆者之前多年的經(jīng)驗(yàn)得出的結(jié)論:遇到即要解決即那就是每遇到一個(gè)問(wèn)題,就馬上解決它,而不是選擇繞過(guò)它。完善當(dāng)前正在使用的代碼,那些還沒有遇到的問(wèn)題,就先不要理它。在當(dāng)前前進(jìn)的道路上,清除所有障礙,以后你肯定還會(huì)再一次走這條路,下次來(lái)到這里的時(shí)候你會(huì)發(fā)現(xiàn)路上不再有障礙。

軟件開發(fā)就是這樣;蛟S解決這個(gè)問(wèn)題需要你多花一點(diǎn)時(shí)間。但是從長(zhǎng)遠(yuǎn)來(lái)看,它會(huì)幫你節(jié)省下更多的時(shí)間。也就是重構(gòu)是個(gè)循序漸進(jìn)的過(guò)程,經(jīng)過(guò)一段時(shí)間之后,你會(huì)發(fā)現(xiàn)之前所有的技術(shù)債務(wù)會(huì)逐步都不見了,所有的坑相繼都被填平了。這種循序漸進(jìn)的代碼重構(gòu)的好處開始顯現(xiàn),編程的速度明顯會(huì)加快。

(3)Code Review時(shí)去重構(gòu),很多公司研發(fā)團(tuán)隊(duì)都會(huì)有定期的Code Review,這種活動(dòng)的好處多多,比如有助于在開發(fā)團(tuán)隊(duì)中傳播知識(shí)進(jìn)行技術(shù)分享,有助于讓較有經(jīng)驗(yàn)的開發(fā)者把知識(shí)傳遞給欠缺經(jīng)驗(yàn)的人,并幫助更多的人對(duì)軟件的其他業(yè)務(wù)模塊更加熟悉從而實(shí)現(xiàn)跨模塊的迭代開發(fā)。Code Review可以讓更多的人有機(jī)會(huì)對(duì)自己提出更多優(yōu)秀好的建議。同時(shí)重構(gòu)可以幫助審查別人的代碼,因?yàn)樵谥貥?gòu)前,你需要先閱讀代碼得到一定程度的理解和熟悉,從而提出一些建議和好的idea,并考慮是否可以通過(guò)重構(gòu)快速實(shí)現(xiàn)自己的好想法,最終通過(guò)重構(gòu)實(shí)踐你會(huì)得到更多的成就感滿足感。為了使審查代碼的工作變得高效有作用,據(jù)我以前的經(jīng)驗(yàn),我建議一個(gè)審查者和一個(gè)原作者進(jìn)行合作,審查者提出修改建議,然后兩人共同判斷這些修改是否能夠通過(guò)重構(gòu)輕松實(shí)現(xiàn),如果修改成本比較低,就在Review的過(guò)程中一起著手修改。

如果是比較大型比較復(fù)雜的設(shè)計(jì)復(fù)查審核工作,建議原作者使用UML類序列圖、時(shí)間序列圖、流程圖去向?qū)彶檎哒宫F(xiàn)設(shè)計(jì)的具體實(shí)現(xiàn)細(xì)節(jié),在整個(gè)Code Review中,審查者可以提出自己的建議或者修改意見。在這種情景下,審查者一般由團(tuán)隊(duì)里面比較資深的工程師、架構(gòu)師、技術(shù)專家等成員組成。

關(guān)于Code Review的形式,還可以采取極限編程中的“結(jié)對(duì)編程”形式。這種形式可以采取兩個(gè)人位置坐在一起去審查代碼,可以采取兩個(gè)平臺(tái)比如IOS 和android 的開發(fā)人員一起去審查,或者經(jīng)驗(yàn)資深的和經(jīng)驗(yàn)不資深的人員一起搭配去審查。

重構(gòu)的這三個(gè)時(shí)機(jī)要把握好原則,即什么時(shí)候不應(yīng)該重構(gòu),比如有時(shí)候既有代碼實(shí)現(xiàn)太混亂啦,重構(gòu)它還不如重新寫一個(gè)來(lái)得簡(jiǎn);此外,如果你的項(xiàng)目已經(jīng)進(jìn)入了尾期,此時(shí)也應(yīng)該避免重構(gòu),這時(shí)機(jī)應(yīng)該盡可能以保持軟件的穩(wěn)定性為主。

理解了重構(gòu)是做什么,重構(gòu)的作用,為什么要重構(gòu),以及重構(gòu)的時(shí)機(jī),我們對(duì)重構(gòu)有了初步認(rèn)識(shí),接下來(lái)筆者重點(diǎn)篇幅來(lái)講解如何使用重構(gòu)技巧去優(yōu)化代碼質(zhì)量達(dá)成Clean Code .

重構(gòu)技巧 — 函數(shù)重構(gòu)

重構(gòu)的源頭一切從重構(gòu)函數(shù)開始,掌握函數(shù)重構(gòu)技巧是重構(gòu)過(guò)程中很關(guān)鍵的一步,接下來(lái)我們來(lái)探討下函數(shù)重構(gòu)有那些實(shí)用技巧。

  • 重命名函數(shù)(Rename Function Name) : Clean Code要求定義的變量和函數(shù)名可讀性要強(qiáng),從名字就可以知道這個(gè)變量和函數(shù)去做什么事情,所以好的可讀性強(qiáng)的函數(shù)名稱很重要,特別是有助于理解比較復(fù)雜的業(yè)務(wù)邏輯。

  • 移除參數(shù)(Remove Parameter): 當(dāng)函數(shù)不再需要某個(gè)參數(shù)時(shí),要果斷移除,不要為了某個(gè)未知需求預(yù)留參數(shù),過(guò)多的參數(shù)會(huì)給使用者帶來(lái)參數(shù)困擾。

  • 將查詢函數(shù)和修改函數(shù)分離:如果某個(gè)函數(shù)既返回對(duì)象值,又修改對(duì)象狀態(tài)。這時(shí)候應(yīng)該建立兩個(gè)不同的函數(shù),其中一個(gè)負(fù)責(zé)查詢,另一個(gè)負(fù)責(zé)修改。如果查詢函數(shù)只是簡(jiǎn)單的返回一個(gè)值而沒有副作用,就可以無(wú)限次的調(diào)用查詢函數(shù)。對(duì)于復(fù)雜的計(jì)算也可以緩存結(jié)果。

  • 令函數(shù)攜帶參數(shù):如果若干函數(shù)做了類似的工作,只是少數(shù)幾個(gè)值不同導(dǎo)致行為略有不同,合并這些函數(shù),以參數(shù)來(lái)表達(dá)不同的值。

  • 以明確函數(shù)取代參數(shù):有一個(gè)函數(shù)其中的邏輯完全取決于參數(shù)值而采取不同行為,針對(duì)該參數(shù)的每一個(gè)可能值建立一個(gè)單獨(dú)的函數(shù)。

  • 保持對(duì)象完整性:如果你需要從某個(gè)對(duì)象取若干值,作為函數(shù)的多個(gè)參數(shù)傳進(jìn)去,特別是需要傳入較多參數(shù)比如5個(gè)參數(shù)或者更多參數(shù)時(shí),這種情況建議直接將這個(gè)對(duì)象直接傳入作為函數(shù)參數(shù),這樣既可以減少參數(shù)的個(gè)數(shù),增加了對(duì)象間的信賴性,而且這樣被調(diào)用者需要這個(gè)對(duì)象的其他屬性時(shí)可以不用人為的再去修改函數(shù)參數(shù)。

  • 以函數(shù)取代參數(shù):對(duì)象調(diào)用某個(gè)函數(shù),并將所得結(jié)果作為參數(shù)傳遞給另外一個(gè)函數(shù),而那個(gè)函數(shù)本身也能夠調(diào)用前一個(gè)函數(shù),直接讓那個(gè)函數(shù)調(diào)用就行,可以直接去除那個(gè)參數(shù),從而減少參數(shù)個(gè)數(shù)。

  • 引入?yún)?shù)對(duì)象:某些參數(shù)總是同時(shí)出現(xiàn),新建一個(gè)對(duì)象取代這些參數(shù),不但可以減少參數(shù)個(gè)數(shù),而且也許還有一些參數(shù)可以遷移到新建的參數(shù)類中,增加類的參數(shù)擴(kuò)展性。

  • 移除設(shè)值函數(shù)(Setting Method):如果類中的某個(gè)字段應(yīng)該在對(duì)象創(chuàng)建時(shí)賦值,此后就不再改變,這種情景下就不需要添加Setting method。

  • 隱藏函數(shù):如果有一個(gè)函數(shù)從來(lái)沒有被其他類有用到,或者是本來(lái)被用到,但隨著類動(dòng)態(tài)添加接口或者需求變更,之后就使用不到了,那么需要隱藏這個(gè)函數(shù),也就是減小作用域。

  • 以工廠函數(shù)取代構(gòu)造函數(shù):如果你希望創(chuàng)建對(duì)象時(shí)候不僅僅做簡(jiǎn)單的構(gòu)建動(dòng)作,最顯而易見的動(dòng)機(jī)就是派生子類時(shí)根據(jù)類型碼創(chuàng)建不同的子類,或者控制類的實(shí)例個(gè)數(shù)。

重構(gòu)技巧 — 條件表達(dá)式

  • 分解條件表達(dá)式:如果有一個(gè)復(fù)雜的條件語(yǔ)句,if/else語(yǔ)句的段落邏輯提取成一個(gè)函數(shù)。

  • 合并條件表達(dá)式:一系列條件測(cè)試,都得到相同的測(cè)試結(jié)果,可以將這些測(cè)試表達(dá)式合并成成一個(gè),并將合并后的表達(dá)式提煉成一個(gè)獨(dú)立函數(shù),如果這些條件測(cè)試是相互獨(dú)立不相關(guān)的,就不要合并。

  • 合并重復(fù)的條件片段:在條件表達(dá)式的每個(gè)分支上有著相同的一段代碼,把這段代碼遷移到表達(dá)式之外。

  • 移除控制標(biāo)記:不必遵循單一出口的原則,不用通過(guò)控制標(biāo)記來(lái)決定是否退出循環(huán)或者跳過(guò)函數(shù)剩下的操作,直接break或者return。

  • 以衛(wèi)語(yǔ)句替代嵌套條件表達(dá)式:條件表達(dá)式通常有兩種表現(xiàn)形式,一:所有分支都屬于正常行為;二:只有一種是正常行為,其他都是不常見的情況。對(duì)于一的情況,應(yīng)該使用if/else條件表達(dá)式;對(duì)于二這種情況,如果某個(gè)條件不常見,應(yīng)該單獨(dú)檢查條件并在該條件為真時(shí)立即從函數(shù)返回,這樣的單獨(dú)檢查常常被稱為衛(wèi)語(yǔ)句。

  • 以多態(tài)取代條件表達(dá)式:如果有個(gè)條件表達(dá)式根據(jù)對(duì)象類型的不同選擇而選擇不同的行為,將條件表達(dá)式的每個(gè)分支放進(jìn)一個(gè)子類內(nèi)的覆寫函數(shù)中,將原始函數(shù)聲明為抽象函數(shù)。

  • 引入Null對(duì)象:當(dāng)執(zhí)行一些操作時(shí),需要再三檢查某對(duì)象是否為NULL,可以專門新建一個(gè)NULL對(duì)象,讓相應(yīng)函數(shù)執(zhí)行原來(lái)檢查條件為NULL時(shí)要執(zhí)行的動(dòng)作,除NULL對(duì)象外,對(duì)特殊情況還可以有Special對(duì)象,這類對(duì)象一般是Singleton.

  • 引入斷言:程序狀態(tài)的一種假設(shè)

  • 以MAP取代條件表達(dá)式:通過(guò)HashMap的Key-Value鍵值對(duì)優(yōu)化條件表達(dá)式,條件表達(dá)式的判斷條件作為key值,value值存儲(chǔ)條件表達(dá)式的返回值。

  • 通過(guò)反射取代條件表達(dá)式:通過(guò)動(dòng)態(tài)反射原理

重構(gòu)技巧 — 案例

前面這多章節(jié)內(nèi)容主要都是理論內(nèi)容,接下來(lái)我們來(lái)看看具體的重構(gòu)案例。

Map去除if條件表達(dá)式

關(guān)于該技巧的實(shí)現(xiàn)方法,上章節(jié)有講述,我們直接看代碼案例如下代碼所示:

原始的條件表達(dá)式代碼如下圖1所示:

public static int getServiceCode(String str){
     int code = 0;
     if(str.equals("Age")){
         code = 1;
     }else if(str.equals("Address")){
         code = 2;
     }else  if(str.equals("Name")){
         code = 3;
     }else if(str.equals("No")){
         code = 4;
     }
     return  code;
 }

重構(gòu)后的代碼如下所示:

public static void initialMap(){
     map.put("Age",1);
     map.put("Address",2);
     map.put("Name",3);
     map.put("No",4);
 }

上述代碼是直接通過(guò)Map結(jié)構(gòu),將條件表達(dá)式分解, Key 是條件變量,Value是條件表達(dá)式返回值。取值很方便,顯然高效率O(1)時(shí)間復(fù)雜度取值。這種重構(gòu)技巧適合于比較簡(jiǎn)單的條件表達(dá)式場(chǎng)景,下面是比較復(fù)雜的沒有返回值的條件表達(dá)式場(chǎng)景,我們?nèi)タ纯慈绾翁幚怼?/p>

反射去除分支結(jié)構(gòu)

原始的條件表達(dá)式代碼如下圖1所示:

(點(diǎn)擊放大圖像)

圖1 條件表達(dá)式示范

(點(diǎn)擊放大圖像)

圖2 通過(guò)Map和反射重構(gòu)示范

如上圖2所示,通過(guò)Map和反射去分解條件表達(dá)式,將條件表達(dá)式分支的邏輯抽取到子類中的覆寫函數(shù)中,提取了共同的抽象類,里面包含抽象接口 handleBusinessData,子類繼承實(shí)現(xiàn)它。

多態(tài)取代條件表達(dá)式

(點(diǎn)擊放大圖像)

圖3 重構(gòu)后的案例結(jié)果圖

(點(diǎn)擊放大圖像)

圖4 重構(gòu)后的案例-多態(tài)如何使用

(點(diǎn)擊放大圖像)

圖5 重構(gòu)后的代碼結(jié)構(gòu)圖

(點(diǎn)擊放大圖像)

圖6 重構(gòu)-抽象類、簡(jiǎn)單工廠模式思想去實(shí)現(xiàn)條件表達(dá)式的分解

如上圖6所示,在原始的條件表達(dá)式中,有兩個(gè)條件表達(dá)式分支(分支邏輯):

  • 中文入住人操作HotelCNPasserngerOperaton類

  • 英文入住人操作HotelEnPassengerOperation 類

共同抽取了基類抽象類:AbstractPassengerOperation,其兩個(gè)分支子類去繼承抽象類。

為了分解條件表達(dá)式,筆者采取了多態(tài)的重構(gòu)技巧去實(shí)現(xiàn),具體有兩種實(shí)現(xiàn)方式,第一種實(shí)現(xiàn)方式是采用抽象類去實(shí)現(xiàn)多態(tài),代碼結(jié)構(gòu)圖如圖5 passenger文件夾,UML類圖如上圖6所示。第二種實(shí)現(xiàn)方式是采用接口去實(shí)現(xiàn)多態(tài),代碼結(jié)構(gòu)如圖5 passenger2 文件夾,UML類圖如上圖7所示。

(點(diǎn)擊放大圖像)

圖7重構(gòu)-接口狀態(tài)者模式思想去實(shí)現(xiàn)條件表達(dá)式的分解

如上圖7所示,在原始的條件表達(dá)式中,有兩個(gè)條件表達(dá)式分支(分支邏輯),其分支邏輯分別放在了子類HotelCNPassengerState 和 HotelENPassengerState中,統(tǒng)一提取了接口類 PassengerState類,里面包含子類都需要實(shí)現(xiàn)的兩個(gè)基礎(chǔ)接口。從圖7,可以看出,是使用了狀態(tài)者模式。

經(jīng)過(guò)了上述重構(gòu)之后,我們達(dá)成了什么效果:

  • 邏輯清晰

  • 主邏輯代碼行數(shù)減少

  • 業(yè)務(wù)邏輯,更好的封裝解藕,無(wú)需關(guān)注具體的業(yè)務(wù)細(xì)節(jié)

  • 采用了多態(tài)、抽象、狀態(tài)模式、工廠模式、Build模式的等不同的思想和方法,很多不同的重構(gòu)技巧去重構(gòu)一個(gè)功能,值得推廣和借簽;

重構(gòu)技巧-移動(dòng)平臺(tái)Android實(shí)戰(zhàn)篇

前面筆者從理論和實(shí)際案例的角度對(duì)重構(gòu)進(jìn)行了分析,包括為什么需要重構(gòu)、重構(gòu)的作用、重構(gòu)的時(shí)機(jī)、如何進(jìn)行重構(gòu)等內(nèi)容,推薦提前閱讀。

接下來(lái)筆者將從實(shí)踐的角度去分享,即在平時(shí)開發(fā)Android工程中,我們?nèi)绾胃咝プ鲋貥?gòu),重構(gòu)和開發(fā)怎么比較好的有效結(jié)合起來(lái)。

Long Method 實(shí)戰(zhàn)

Long Method 是筆者前面提到的“代碼壞味道”之一,這也是開發(fā)者一般經(jīng)常容易犯的典型錯(cuò)誤。

接下來(lái)筆者介紹在Android平臺(tái)中如何去解決這個(gè)“bad taste”,實(shí)際上我們可以通過(guò)計(jì)算函數(shù)的圈復(fù)雜度(cyclomatic complexity)來(lái)判斷函數(shù)是否過(guò)長(zhǎng),一般cyclomatic complexity > 11 ,就可以認(rèn)為函數(shù)過(guò)長(zhǎng),需要進(jìn)行重構(gòu)優(yōu)化,那么關(guān)于函數(shù)重構(gòu)的優(yōu)化技巧在前面幾章我也有重點(diǎn)提到。

在解決圈復(fù)雜度過(guò)大這個(gè)問(wèn)題,首先我們要去發(fā)現(xiàn)你的工程哪里存在問(wèn)題,這一步我們可以通過(guò)工具或者第三方插件幫我們?nèi)ソ鉀Q,比如打開Android studio 工具欄 Analyze –> Run inspection by name,如下圖8所:

(點(diǎn)擊放大圖像)

圖8 Analyze工具示意圖

如圖8所示,選擇Run inspection by name ,打開如下圖9所示界面:

(點(diǎn)擊放大圖像)

圖9 Overly long method 界面示意圖

如圖9所示,輸入long 出現(xiàn)Overly long method ,選擇如上圖所示,點(diǎn)擊會(huì)打開一個(gè)新的界面如圖10所示:

(點(diǎn)擊放大圖像)

圖10 Run ‘Overly long method’

如圖10所示,可以選擇對(duì)當(dāng)前工程,當(dāng)前File,當(dāng)前Module 或者其他Module進(jìn)行分析,等待運(yùn)行一段時(shí)間分析結(jié)果如下圖11所示:

(點(diǎn)擊放大圖像)

圖11 Run ‘Overly long method’ 結(jié)果

得到圖11分析結(jié)果之后,我們就可以有針對(duì)性的去進(jìn)行優(yōu)化重構(gòu)了,知道哪些類哪些函數(shù)需要去優(yōu)化,具體重構(gòu)優(yōu)化是一般可以將過(guò)長(zhǎng)的函數(shù)拆分成幾個(gè)不同的小函數(shù),拆分原則:一個(gè)函數(shù)的功能要保持職責(zé)單一,查詢和修改職責(zé)分開;所以可以通過(guò)不同類型的功能業(yè)務(wù)邏輯處理或者查詢、修改功能去拆分大函數(shù)。

Too many parameters 實(shí)戰(zhàn)

函數(shù)參數(shù)過(guò)多,也是典型的“代碼壞味道”之一,同理打開如上圖8所示的界面,然后輸入 too many pa 關(guān)鍵字打開如下圖12所示的界面:

(點(diǎn)擊放大圖像)

圖12 Analyze too many pa 關(guān)鍵字界面

選擇圖中所示的 “Method with too many parameters”,會(huì)出現(xiàn)如上圖10所示的界面,然后選擇“Whole Project”,運(yùn)行之后,分析得到的結(jié)果如下圖13所示:

(點(diǎn)擊放大圖像)

圖13 “Too many parameters”結(jié)果分析圖

Redundant local variable 實(shí)戰(zhàn)

冗余的局部變量,同樣是造成代碼壞味道的源頭,輸入 “Redudant  關(guān)鍵字”,同理執(zhí)行得出分析結(jié)果如下圖14所示,然后我們根據(jù)分析后的結(jié)果有針對(duì)性的去重構(gòu)優(yōu)化:

(點(diǎn)擊放大圖像)

圖14 冗余局部變量分析結(jié)果

Unused Declaration –無(wú)用函數(shù)實(shí)戰(zhàn)

無(wú)用函數(shù)是“代碼壞味道”來(lái)源之一,很多函數(shù)因?yàn)闅v史遺留的原因,需求已經(jīng)下線了但是代碼還在遺留在工程里面,或者因?yàn)橹貥?gòu),歷史遺留代碼沒有完全刪除或者想暫時(shí)留著下個(gè)版本使用,這些都是不好的習(xí)慣,不用的代碼應(yīng)該立即刪除,而不應(yīng)該保留在工程項(xiàng)目中。

同理打開如上圖8所示的界面,然后輸入 Unused declaration關(guān)鍵字打開如下圖15所示的界面:

(點(diǎn)擊放大圖像)

圖15 Unused declaration

分析結(jié)果能得出你整個(gè)工程中沒有被使用的函數(shù),我們都可以刪除掉。

無(wú)用函數(shù)參數(shù)-實(shí)戰(zhàn)

同理,輸入關(guān)鍵字 Unused method parameter, 如下圖16所示, 執(zhí)行可以分析出工程中有哪些函數(shù)存在無(wú)用參數(shù),可以針對(duì)性的進(jìn)行優(yōu)化。

(點(diǎn)擊放大圖像)

圖16 unused method parameter

infer 實(shí)戰(zhàn)

Infer 是Facebook開源的靜態(tài)代碼檢查工具,可檢查 Android 和 Java 代碼中的 NullPointException 和 資源泄露。除了以上,Infer 還可發(fā)現(xiàn) iOS 和 C 代碼中的內(nèi)存泄露,內(nèi)存泄露,內(nèi)存泄露。

Android studio 已經(jīng)將infer集成到工具欄里面,點(diǎn)擊Analyze->infer Nullity,執(zhí)行分析得出的界面類似如下圖17所示:

(點(diǎn)擊放大圖像)

圖17 infer Nullity 分析結(jié)果圖

點(diǎn)擊圖17所示的分析結(jié)果具體項(xiàng),可以定位到具體的代碼文件,然后我們?nèi)ナ謩?dòng)判斷 或者直接點(diǎn)擊“Infer Nullity Annotations”,工具直接幫我去完成改造結(jié)果。

第三方插件與Android studio 的集成

FindBugs 集成

FindBugs是一個(gè)開源的靜態(tài)代碼分析工具,基于LGPL開源協(xié)議,無(wú)需運(yùn)行工程就能對(duì)代碼進(jìn)行分析的工具。它不注重style及format,注重檢測(cè)真正的bug及潛在的性能問(wèn)題 ,以bytecode(*.class、*.jar)為對(duì)象進(jìn)行檢查。除了單獨(dú)運(yùn)行,還可以用作Android-studio 和Eclipse 的Plug-in,以及嵌入Ant或者M(jìn)aven作為task之一進(jìn)行運(yùn)行。

Findbugs自帶60余種Bad practice,80余種Correntness,1種Internationalization,12種Malicious code vulnerability,27種Multithreaded correntness,23種Performance,43種Dodgy。它可以檢測(cè)檢測(cè)java programing中容易陷入的bug pattern,比如 equals() 實(shí)現(xiàn)時(shí)的一般規(guī)約違反Null pointer的參照 ,Method的返回值的check遺漏 ,初始化前field的訪問(wèn), Multi-thread的正確性,無(wú)條件的wait,Code的脆弱性 ,可以變更的靜態(tài)object ,內(nèi)部數(shù)列參照的return等。

Android Studio 可以通過(guò)插件的方式安裝,具體是打開Android Studio->Preference –>搜索plugin 選擇 Plugins Tab ,打開界面如下圖17所示:

(點(diǎn)擊放大圖像)

圖17 搜索FindBugs-IDEA界面

如上圖17中,點(diǎn)擊install ,downloading plugin install ,然后重啟Android studio ,會(huì)有提示界面如下圖18所示:

(點(diǎn)擊放大圖像)

圖18 Android FindBugs Enable

點(diǎn)擊“Enable Android FindBugs”,會(huì)打開界面,在見面中添加Plugin For Android FindBugs即可。

然后在Android Studio工具欄上,打開如下圖19所示的界面:

(點(diǎn)擊放大圖像)

圖19 FindBugs 入口界面

如上圖19所示,可以分析對(duì)前的文件,可以分析一個(gè)Module files ,也可以分析一個(gè)工程文件,選擇一項(xiàng)會(huì)得出分析結(jié)果如下圖20所示:

(點(diǎn)擊放大圖像)

圖20 FindBugs分析結(jié)果圖

根據(jù)圖20所示的結(jié)果,我們可以查看具體的Bug details ,存在什么問(wèn)題,然后具體跟蹤到對(duì)應(yīng)的代碼,根據(jù)對(duì)應(yīng)的建議去修改。

MetricsReloaded 集成

MetricsReloaded是一個(gè)計(jì)算代碼復(fù)雜度即圈復(fù)雜度的Jetbrain開源開發(fā)的第三方插件。關(guān)于代碼復(fù)雜度,有個(gè)維度的衡量,在這里需要普及下軟件復(fù)雜度的相關(guān)知識(shí):基本復(fù)雜度(Essential Complexity (ev(G))、模塊設(shè)計(jì)復(fù)雜度(Module Design Complexity (iv(G)))、Cyclomatic Complexity (v(G))圈復(fù)雜度。

ev(G)基本復(fù)雜度是用來(lái)衡量程序非結(jié)構(gòu)化程度的,非結(jié)構(gòu)成分降低了程序的質(zhì)量,增加了代碼的維護(hù)難度,使程序難于理解。因此,基本復(fù)雜度高意味著非結(jié)構(gòu)化程度高,難以模塊化和維護(hù)。實(shí)際上,消除了一個(gè)錯(cuò)誤有時(shí)會(huì)引起其他的錯(cuò)誤。

Iv(G)模塊設(shè)計(jì)復(fù)雜度是用來(lái)衡量模塊判定結(jié)構(gòu),即模塊和其他模塊的調(diào)用關(guān)系。軟件模塊設(shè)計(jì)復(fù)雜度高意味模塊耦合度高,這將導(dǎo)致模塊難于隔離、維護(hù)和復(fù)用。模塊設(shè)計(jì)復(fù)雜度是從模塊流程圖中移去那些不包含調(diào)用子模塊的判定和循環(huán)結(jié)構(gòu)后得出的圈復(fù)雜度,因此模塊設(shè)計(jì)復(fù)雜度不能大于圈復(fù)雜度,通常是遠(yuǎn)小于圈復(fù)雜度。

v(G)是用來(lái)衡量一個(gè)模塊判定結(jié)構(gòu)的復(fù)雜程度,數(shù)量上表現(xiàn)為獨(dú)立路徑的條數(shù),即合理的預(yù)防錯(cuò)誤所需測(cè)試的最少路徑條數(shù),圈復(fù)雜度大說(shuō)明程序代碼可能質(zhì)量低且難于測(cè)試和維護(hù),經(jīng)驗(yàn)表明,程序的可能錯(cuò)誤和高的圈復(fù)雜度有著很大關(guān)系。

同理,如上圖17所示一樣去安裝MetricsReloaded插件,安裝成功后執(zhí)行Analyze->Calculate Metrics,打開如下圖21所示的界面:

(點(diǎn)擊放大圖像)

圖21 Calculate Metrics 界面

如上圖所示,選擇Complexity metrics,執(zhí)行分析結(jié)果如下圖22所示:

(點(diǎn)擊放大圖像)

圖22 Calculate Metrics 分析結(jié)果圖

如上圖22所示界面中的紅顏色部分,代表需要去重構(gòu)優(yōu)化的,點(diǎn)擊當(dāng)前行,會(huì)定位到源代碼,然后我們針對(duì)性去優(yōu)化函數(shù)。上圖中,可以分析出方法的圈復(fù)雜度、類的圈復(fù)雜度、包的圈復(fù)雜度、模塊的圈復(fù)雜度、工程的圈復(fù)雜度。

Sonar 集成

對(duì)于Android(Java)工程,Sonar官方提供了Java Plugin和Java-specific Plugins,這些插件可以實(shí)現(xiàn)大部分Findbugs、PMD、Checkstyle、Android Lint等的檢查規(guī)則。主要可以從以下幾個(gè)方面檢測(cè)代碼質(zhì)量:

(1)復(fù)雜度:項(xiàng)目中方法、類、文件的復(fù)雜度分布情況;

(2)重復(fù):展示代碼中重復(fù)嚴(yán)重的地方;

(3)單元測(cè)試覆蓋率:統(tǒng)計(jì)并展示單元測(cè)試覆蓋率(主要用于java工程);

(4)代碼標(biāo)準(zhǔn):通過(guò)PMD、CheckStyle等代碼規(guī)則檢測(cè)工具規(guī)范代碼編寫;

(5)代碼注釋:沒有注釋或者過(guò)多的注釋都不是一個(gè)良好的編程習(xí)慣;

(6)潛在的bug: 通過(guò)PMD、Findbugs等代碼檢測(cè)工具檢測(cè)出潛在的bug;

(7)架構(gòu)設(shè)計(jì):可以檢測(cè)耦合、依賴關(guān)系、架構(gòu)規(guī)則、管理第三方的jar包等。

集成Sonar之后,我們需要著種解決的就是代碼重復(fù)率問(wèn)題,這也是“代碼壞味道”最典型的問(wèn)題,開發(fā)者最容易犯這個(gè)問(wèn)題,特別是不少開發(fā)者喜歡偷懶,容易拷貝來(lái)拷貝去,造成工程代碼的重復(fù)率比較高。一次構(gòu)建運(yùn)行之后,我們可以得出分析結(jié)果,類似如下圖23所示:

(點(diǎn)擊放大圖像)

圖23 sonar構(gòu)建運(yùn)行結(jié)果

點(diǎn)擊重復(fù)率,我們可以看出哪些文件之間的代碼是重復(fù)的,然后針對(duì)性使用抽取工具類、合并類、合并分解函數(shù)等技術(shù)重構(gòu)手段去優(yōu)化。

SonarLint集成

前面我們所講到的Sonar之前的提供的本地工具是需要依賴SonarQube服務(wù)器的,這樣導(dǎo)致其運(yùn)行速度緩慢。 新出的SonarLint的掃描引擎直接安裝在本地,速度超快,實(shí)時(shí)探測(cè)代碼技術(shù)債務(wù),給程序員最快速的反饋,排除代碼異味的絕佳利器,幫助程序員獲得Clean code。 新版SonarLint也能鏈接SonarQube服務(wù)器,但這并不必要。本地安裝SonarLint來(lái)做代碼本地掃描,本地發(fā)現(xiàn)本地修改,而且能快速看到修改結(jié)果,快速處理代碼臭味,有效控制技術(shù)債務(wù)。

按照如上圖17所示一樣去安裝SonarLint插件,安裝之后重啟Android Studio ,即可動(dòng)態(tài)掃描出結(jié)果如下圖24所示:

(點(diǎn)擊放大圖像)

圖24 SonarLint掃描結(jié)果圖

重構(gòu)技巧實(shí)戰(zhàn)-小結(jié)

本文我們講述了在Android程序開發(fā)過(guò)程中如何結(jié)合工具去幫助我們做重構(gòu)優(yōu)化的各種技能包括Android Studio自己已經(jīng)集成的插件Code Inspection 、infer Nullity以及FindBugs、MetricsReloaded、Sonar、SonarLint等第三方插件工具,其實(shí)還有很多類似著名的插件比如QAPlugin、PMD、Hammurapi 、Lint4j等工具,大家可以自行嘗試使用,在這里我不一一說(shuō)明。

所謂工欲善其事必先利就是這個(gè)道理,我們?nèi)绻枰プ鲋貥?gòu)優(yōu)化,首先我們要知道我們做的不好的地方-代碼的壞味道在哪里,這種工作如果靠人為手動(dòng)的去發(fā)現(xiàn),那么效率和產(chǎn)出將會(huì)及其低下,所以我們需要借助于集成插件工具幫我們自動(dòng)去掃描發(fā)現(xiàn)問(wèn)題,然后再去針對(duì)性的重構(gòu)優(yōu)化,產(chǎn)出Clean code 。

寫在最后

重構(gòu)是一門比較大而深的話題和課題,筆者這次主要探討了如何通過(guò)有效的重構(gòu)技巧去寫成優(yōu)秀的整潔代碼,代碼整潔之道就是要將重構(gòu)始終貫穿在整個(gè)開發(fā)過(guò)程中,不斷的持續(xù)的漸進(jìn)重構(gòu),從而將以前的技術(shù)債全部還完。

重構(gòu)是個(gè)技術(shù)活,需要很資深的人士去整體架構(gòu)把控技術(shù)方案和產(chǎn)品質(zhì)量,才能使重構(gòu)做的更加有效并且不會(huì)引入新的問(wèn)題,但是無(wú)論我們最終采取什么手段去重構(gòu),最終我們都需要盡量符合Solid設(shè)計(jì)相關(guān)原則:

  • 類的單一職責(zé):體現(xiàn)了類只應(yīng)該做一件事,良好的軟件設(shè)計(jì)中系統(tǒng)是由一組大量的短小的類組成,以及需要他們之間功能協(xié)作完成,而不是幾個(gè)上帝類。如果類的職責(zé)超過(guò)一個(gè),這些職責(zé)之間就會(huì)產(chǎn)生耦合。改變一個(gè)職責(zé),可能會(huì)影響和妨礙類為其他人服務(wù)的功能。這種類型的耦合將會(huì)導(dǎo)致脆弱的設(shè)計(jì),在修改的時(shí)候可能會(huì)引入不少未知的問(wèn)題。

  • 開閉原則:其定義是說(shuō)一個(gè)軟件實(shí)體如類,模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開放,而對(duì)修改關(guān)閉,具體來(lái)說(shuō)就是你應(yīng)該通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改原有的代碼來(lái)實(shí)現(xiàn)變化,該原則是面相對(duì)象設(shè)計(jì)最基本的原則。其指導(dǎo)思想就是(1)抽象出相對(duì)穩(wěn)定的接口,這部分應(yīng)該不動(dòng)或者很少改動(dòng);(2)封裝變化;不過(guò)在軟件開發(fā)過(guò)程中,要一開始就完全按照開閉原則來(lái)可能比較困難,更多的情況是在不斷的迭代重構(gòu)過(guò)程中去改進(jìn),在可預(yù)見的變化范圍內(nèi)去做設(shè)計(jì)。

  • 里氏替換原則:子類可以擴(kuò)展父類的功能,但不能改變父類原有的功能。簡(jiǎn)單來(lái)說(shuō),所有使用基類代碼的地方,如果換成子類對(duì)象的時(shí)候還能夠正常運(yùn)行,則滿足這個(gè)原則,否則就是繼承關(guān)系有問(wèn)題,應(yīng)該廢除兩者的繼承關(guān)系,這個(gè)原則可以用來(lái)判斷我們的對(duì)象繼承關(guān)系是否合理。通常在設(shè)計(jì)的時(shí)候,我們都會(huì)優(yōu)先采用組合而不是繼承,因?yàn)槔^承雖然減少了代碼,提高了代碼的重用性,但是父類跟子類會(huì)有很強(qiáng)的耦合性,破壞了封裝。

  • 接口隔離原則:不能強(qiáng)迫用戶去依賴那些他們不使用的接口。簡(jiǎn)單來(lái)說(shuō)就是客戶端需要什么接口,就提供給它什么樣的接口,其它多余的接口就不要提供,不要讓接口變得臃腫,否則當(dāng)對(duì)象一個(gè)沒有使用的方法被改變了,這個(gè)對(duì)象也將會(huì)受到影響。接口的設(shè)計(jì)應(yīng)該遵循最小接口原則,其實(shí)這也是高內(nèi)聚的一種表現(xiàn),換句話說(shuō),使用多個(gè)功能單一、高內(nèi)聚的接口總比使用一個(gè)龐大的接口要好。

  • 依賴倒置(DIP):高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié);細(xì)節(jié)應(yīng)該依賴抽象。其實(shí)這就是我們經(jīng)常說(shuō)的“針對(duì)接口編程”,這里的接口就是抽象,我們應(yīng)該依賴接口,而不是依賴具體的實(shí)現(xiàn)來(lái)編程。DIP描述組件之間高層組件不應(yīng)該依賴于底層組件。依賴倒置是指實(shí)現(xiàn)和接口倒置,采用自頂向下的方式關(guān)注所需的底層組件接口,而不是其實(shí)現(xiàn)。DI模式很好例子的就是應(yīng)用IOC(控制反轉(zhuǎn))框架,構(gòu)造方式分為分構(gòu)造注入,函數(shù)注入,屬性注入 。

當(dāng)我們?cè)谧鲋貥?gòu)優(yōu)化的時(shí)候應(yīng)該充分考慮上面這幾個(gè)原則,一開始可能設(shè)計(jì)并不完美,不過(guò)可以在重構(gòu)的過(guò)程中不斷完善。但其實(shí)很多人都跳過(guò)了設(shè)計(jì)這個(gè)環(huán)節(jié),拿到一個(gè)模塊直接動(dòng)手編寫代碼,更不用說(shuō)去思考設(shè)計(jì)了,項(xiàng)目中也有很多這樣的例子。當(dāng)然對(duì)于簡(jiǎn)單的模塊或許不用什么設(shè)計(jì),不過(guò)假如模塊相對(duì)復(fù)雜的話,能夠在動(dòng)手寫代碼之前好好設(shè)計(jì)思考一下,養(yǎng)成這個(gè)習(xí)慣,肯定會(huì)對(duì)編寫出可讀性、穩(wěn)定性、健壯性、靈活性、可服用性、可擴(kuò)展性較高的代碼有幫助。

感謝徐川對(duì)本文的審校。

給InfoQ中文站投稿或者參與內(nèi)容翻譯工作,請(qǐng)郵件至[email protected]。也歡迎大家通過(guò)新浪微博(@InfoQ,@丁曉昀),微信(微信號(hào): InfoQChina )關(guān)注我們。

 

來(lái)自:http://www.infoq.com/cn/articles/clean-code-refactor

 

標(biāo)簽: ssd 代碼 服務(wù)器 開發(fā)者 搜索 推廣 移動(dòng)平臺(tái)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:從源頭入手,一分鐘秒懂為什么要搞微服務(wù)架構(gòu)?

下一篇:軟件架構(gòu)設(shè)計(jì)中要注意的六個(gè)方面