姓名:榮皓宇
學(xué)號:17101223406
轉(zhuǎn)載自開發(fā)者頭條app: http://mp.weixin.qq.com/s/dDR21k30s6ZVfDvl8BVQmA,有部分刪改
【嵌牛導(dǎo)讀】:阿里官方的Java代碼規(guī)范標(biāo)準,這份開發(fā)手冊不僅規(guī)范了一些開發(fā)細節(jié),也提出了很多工程開發(fā)的哲學(xué),
幾乎日常Java開發(fā)中方方面面都有所涉及,每一條都是前人踩過的坑,通過血的教訓(xùn)總結(jié)出來的。
本文就其中分支選擇的規(guī)范做了一些思考
【嵌牛鼻子】:代碼規(guī)范,if-else,圈復(fù)雜度
【嵌牛提問】:switch語句是否也符合文中所述的策略模式?
【嵌牛正文】:
阿里Java開發(fā)手冊下載鏈接: https://yq.aliyun.com/articles/69327?utm_content=m_10088
阿里JAVA開發(fā)手冊已經(jīng)發(fā)表有很長時間了,值得認真研究思考推廣
阿里官方的Java代碼規(guī)范標(biāo)準,這份開發(fā)手冊不僅規(guī)范了一些開發(fā)細節(jié),也提出了很多工程開發(fā)的哲學(xué),值得好好閱讀。
可謂包羅萬象,幾乎日常Java開發(fā)中方方面面都有所涉及。
每一條都是前人踩過的坑,通過血的教訓(xùn)總結(jié)出來的。
能公布出來真是造福全部Java開發(fā)者。
開發(fā)手冊詳細列舉如何開發(fā)更加高效,更加容錯,更加有協(xié)作性,力求知其然,更知其不然,結(jié)合正反例,提高代碼質(zhì)量。比如,異常日志處理時的各種不規(guī)范行為;集合轉(zhuǎn)換的各種坑;創(chuàng)建線程池出現(xiàn)的等待隊列OOM等。
的確阿里JAVA開發(fā)手冊值得我們好好閱讀和思考,每一條都是前人踩過的坑,通過血的教訓(xùn)總結(jié)出來的。所以今天就其中一點自己的思考理解進行分享。
看完這條,個人覺得主要是圈復(fù)雜度,由于代碼是人寫的,并且需要人來進行維護,如果足夠的復(fù)雜的話,那么編寫出現(xiàn)錯誤的可能性都很大,并且維護理解起來難度也非常高,以及后期如果需要擴展本來就很復(fù)雜再加一個很簡單的功能都變得很困難(相信大家一定都有這樣的經(jīng)歷)。
圈復(fù)雜度
圈復(fù)雜度(Cyclomatic complexity)是一種代碼復(fù)雜度的衡量標(biāo)準。在軟件測試的概念里,圈復(fù)雜度用來衡量一個模塊判定結(jié)構(gòu)的復(fù)雜程度,數(shù)量上表現(xiàn)為獨立線性路徑條數(shù),即合理的預(yù)防錯誤所需測試的最少路徑條數(shù)。圈復(fù)雜度大說明程序代碼可能質(zhì)量低且難于測試和維護,根據(jù)經(jīng)驗,程序的可能錯誤和高的圈復(fù)雜度有著很大關(guān)系。
看看上面阿里JAVA開發(fā)手冊里面提到的,如果非得使用if()...else if()...else...方式表達邏輯,【強制】避免后續(xù)代碼維護困難,請匆超過3層。如果超過3層的if-else的邏輯判斷代碼可以使用衛(wèi)語句、策略模式、狀態(tài)模式等來實現(xiàn)。
其實在我看來,使用衛(wèi)語句、策略模式、狀態(tài)模式就是來降低圈復(fù)雜度,讓代碼更加簡單,這樣不管是編寫代碼人員以及維護人員都可以非常方便了解到本質(zhì)意思。
雖然阿里JAVA開發(fā)手冊提到的是if()...else if()...else...方式表達邏輯,延伸下,關(guān)于多次嵌套循環(huán)等道理也一樣,需要考慮優(yōu)化的。
思路分析
如上圖,其實看起來就是一顆樹結(jié)構(gòu),相對來說其實比較復(fù)雜了,優(yōu)化的思路其實就是把樹結(jié)構(gòu)變成順序結(jié)構(gòu)即可,那樣條理就清晰了,總體思路是這樣的,下面看看使用衛(wèi)語句、策略模式、狀態(tài)模式怎么達到的。
衛(wèi)語句
衛(wèi)語句?衛(wèi)語句就是把復(fù)雜的條件表達式拆分成多個條件表達式,比如一個很復(fù)雜的表達式,嵌套了好幾層的if - then-else語句,轉(zhuǎn)換為多個if語句,實現(xiàn)它的邏輯,這多條的if語句就是衛(wèi)語句。
其中衛(wèi)語句示例如下:
publicvoidtoday(){
if(isBusy()){
System.out.println("change time.");
return;
}
if(isFree()){
System.out.println("go to travel.");
return;
}
System.out.println("stay at home to learn Alibaba Java Coding Guidelines.");
return;
}
其實這個比較簡單,每一個if對應(yīng)葉子節(jié)點的一條路徑(每個if基本就return了)。
策略模式
概述:使用這個模式來將一組算法封裝成一系列對象。通過傳遞這些對象可以靈活的改變程序的功能。
策略模式比較有名的就是諸葛亮的三個錦囊妙計說起,如圖:
諸葛亮為什么要這么麻煩,做三個錦囊?他完全可以只做一個錦囊,將這三個妙計都寫在它上面。可他沒有這么做,而是正確的運用了策略模式做了三個錦囊。這樣做的好處十分明顯:諸葛亮一個錦囊寫一個妙計,他的思路十分清晰,不會三個計策相互混亂。而趙云看妙計的時候也十分方便,什么時候看哪個妙計,使用十分方便,如果三個妙計混在一起,他就沒這么方便了。
在JDK中java.util.Comparator#compare()就是使用的策略模式,比如我們經(jīng)常對商品進行排序,條件有很多啊,按照商品瀏覽量、價格、更新時間、【價格、時間】、【瀏覽量、更新時間】(進行升序、降序操作)其實這個也是上面那顆樹,需要做的就是每次取其中一條葉子節(jié)點。很多時候這些判斷都是寫在一個公用的方法里面,進行大量的判斷之后寫排序,而JDK怎么做的呢?把變化的比較判斷拿出來,其實判斷樹中每個葉子結(jié)點就是一種策略,想象我們平時怎么做的呢? 都是把Comparator#compare()寫好(可能有很多實現(xiàn)Comparator接口的排序算法)每次我們調(diào)用的時候選擇其中一種即可。
與衛(wèi)語句不同的是,衛(wèi)語句把每一個if對應(yīng)葉子節(jié)點的一條路徑。而策略模式是所以葉子都在實現(xiàn)Comparator接口了,具體開始用那個是調(diào)用的直接用(所以不會像衛(wèi)語句那樣看見很多if了)
狀態(tài)模式
概述:當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。主要解決的是對象的行為依賴于它的狀態(tài)(屬性),并且可以根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為。
封裝了轉(zhuǎn)換規(guī)則。
枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類。
將所有與某個狀態(tài)有關(guān)的行為放到一個類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為。
允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體,而不是某一個巨大的條件語句塊。
可以讓多個環(huán)境對象共享一個狀態(tài)對象,從而減少系統(tǒng)中對象的個數(shù)。
由于狀態(tài)模式是封裝了轉(zhuǎn)換規(guī)則,所以一般樹的深度最少需要2層以及上,個人理解的感覺就是一個流程了,比如*水低于0度是冰的狀態(tài)--> 大于0度又變成液態(tài)--> 100度又變成沸騰的狀態(tài)
狀態(tài)模式與策略模式很像,策略模式是外驅(qū)動,而狀態(tài)模式是內(nèi)驅(qū)動。本質(zhì)也是把判斷樹里面只取其中一條葉子的路徑。
狀態(tài)模式有一個明顯的缺點:狀態(tài)模式對"開閉原則"的支持并不太好,對于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類需要修改那些負責(zé)狀態(tài)轉(zhuǎn)換的源代碼,否則無法切換到新增狀態(tài),而且修改某個狀態(tài)類的行為也需修改對應(yīng)類的源代碼。
程序員笑話
老婆給當(dāng)程序員的老公打電話:下班順路買十個包子,如果看到賣西瓜的,買一個。當(dāng)晚老公手捧一個包子進了家門…老婆怒道:你怎么只買一個包子?!老公甚恐,喃喃道:因為我真看到賣西瓜的了。”
如果使用策略模式就簡單了,2條信息,1:買十個包子。2:買一個西瓜,沒有就算了。雖然是個笑話,但是順序的就是比判斷的要簡單。
總結(jié)
圈復(fù)雜度概念
衛(wèi)語句
策略模式
狀態(tài)模式
匯總:本質(zhì)就是把較深的判斷樹,使用的時候,就是把判斷樹結(jié)構(gòu)變成順序結(jié)構(gòu)即可,就是給出每個葉子的路徑而不需要看起來是一顆復(fù)雜的樹結(jié)構(gòu)。
思考
這是阿里JAVA開發(fā)手冊其中一條明細