原創(chuàng)文章,轉(zhuǎn)載請注明:轉(zhuǎn)載自Keegan小鋼 微信訂閱號:keeganlee_me 寫于2015-06-19
Android項目重構(gòu)之路:架構(gòu)篇 Android項目重構(gòu)之路:界面篇 Android項目重構(gòu)之路:實現(xiàn)篇
在前一篇文章《Android項目重構(gòu)之路:架構(gòu)篇》中已經(jīng)簡單說明了項目的架構(gòu),將項目分為了四個層級:模型層、接口層、核心層、界面層。其中,最上層的界面,是變化最頻繁的一個層面,也是最復(fù)雜最容易出問題的一個層面,如果規(guī)劃不好,很容易做著做著,又亂成一團(tuán)了。 要規(guī)劃好界面層,至少應(yīng)該遵循幾條基本的原則: 保持規(guī)范性:定義好開發(fā)規(guī)范,包括書寫規(guī)范、命名規(guī)范、注釋規(guī)范等,并按照規(guī)范嚴(yán)格執(zhí)行; 保持單一性:布局就只做布局,內(nèi)容就只做內(nèi)容,各自分離好;每個方法、每個類,也只做一件事情; 保持簡潔性:保持代碼和結(jié)構(gòu)的簡潔,每個方法,每個類,每個包,每個文件,都不要塞太多代碼或資源,感覺多了就應(yīng)該拆分。
規(guī)范性
每個人的編碼習(xí)慣和風(fēng)格都不同,不說那些缺乏良好編碼習(xí)慣的開發(fā)人員,就連那些已經(jīng)養(yǎng)成良好編碼習(xí)慣的人員,很多方面都會不同。比如縮進(jìn),有的喜歡4個空格,有的喜歡兩個空格;比如變量名,有的喜歡m開頭,例如mValue,有的喜歡直接就命名為value。如果不設(shè)定好規(guī)范,讓每個人都按照自己的習(xí)慣和風(fēng)格去編碼,久了肯定亂,尤其當(dāng)團(tuán)隊中存在還沒養(yǎng)成良好編碼習(xí)慣的人員時,更容易亂。所謂無規(guī)矩不成方圓,若無規(guī)范,久必亂。定義好規(guī)范,才能統(tǒng)一風(fēng)格,才可提高代碼可讀性,同時也提高了維護(hù)性,還減低了引入bug的機(jī)會。 開發(fā)規(guī)范并沒有統(tǒng)一的標(biāo)準(zhǔn),在這里,我只是根據(jù)自己的經(jīng)驗對一些點提供一點建議,僅供參考。 縮進(jìn)很多人都習(xí)慣用Tab縮進(jìn),不管是規(guī)范4個空格還是2個空格,統(tǒng)一設(shè)置好Tab縮進(jìn)的size就好了,這樣就不用讓每個人都去敲空格。 命名一個好的命名,一眼就可以從名字中看到它是干嘛的,做什么用,什么類型等等。舉個id命名的例子,看到有些團(tuán)隊喜歡將一些控件縮寫,比如TextView縮寫為tv,ListView縮寫為lv,這種縮寫倒是挺簡潔的,但是并不能一眼就能看出它是什么,對于不熟悉的人來說,誰知道tv和lv是什么啊,還不如用text和list更明確些。我喜歡的id命名結(jié)構(gòu)為:控件_范圍_功能,例如:edit_login_password,這是一個登錄頁的密碼輸入框。 單位文字大小的單位應(yīng)該統(tǒng)一用sp,其他元素用dp。因為這兩個單位是與設(shè)備分辨率無關(guān)的,能夠解決在不同分辨率設(shè)備上顯示效果不同的問題。另外,SDK里面,對文字大小系統(tǒng)默認(rèn)是用sp單位的,但其他元素單位默認(rèn)卻不是dp,而是px的,同時也沒有提供dp的設(shè)置接口,所以,自己寫兩個dp和px轉(zhuǎn)換的方法是很有必要的。
最重要的并不在于規(guī)范怎么定義,而是在于規(guī)范的嚴(yán)格執(zhí)行。如果規(guī)范定義好了,但卻不遵守,那規(guī)范就等于形同虛設(shè),因此,規(guī)范一旦設(shè)定,就要嚴(yán)格執(zhí)行。 單一性
我們都知道,面向?qū)ο笤O(shè)計中,有一個基本原則就是單一職責(zé)原則,它規(guī)定一個類應(yīng)該只有一個發(fā)生變化的原因。而這里說的單一性,不只是規(guī)定類,也規(guī)定了方法、包,甚至到最大層面的分層架構(gòu)。保持單一性是減低耦合度的關(guān)鍵標(biāo)準(zhǔn),其目的就是各方面的解耦。架構(gòu)上的分層就是最大層面的解耦,而方法上的單一就是最小層面的解耦了。 界面的單一界面上的單一,首先是界面的布局和界面的數(shù)據(jù)應(yīng)該分離。這一點,Android已經(jīng)用layout和Activity做好解耦了,我們只要確保用layout文件排好布局,在Activity展示數(shù)據(jù)就好了。另外,界面數(shù)據(jù)的獲取和展示也應(yīng)該分離。很多開發(fā)團(tuán)隊習(xí)慣將數(shù)據(jù)的獲取和展示都放在Activity或Fragment里完成的,架構(gòu)篇的讀者里也有人反映了這個情況,請求接口、獲取數(shù)據(jù)、檢查數(shù)據(jù)、顯示數(shù)據(jù)更新UI,全都在界面上完成的。這樣子的話,當(dāng)數(shù)據(jù)的獲取發(fā)生改變時,比如要添加緩存,這時候界面就需要改動了,當(dāng)數(shù)據(jù)的展示也需要修改時,比如某個控件要展示其他數(shù)據(jù),界面也一樣需要改動,也就是說,界面上已經(jīng)有兩個發(fā)生變化的原因,這就違反了單一職責(zé)原則。 界面上的單一,就是要保持界面上每個維度都做好分離,從界面的布局,到數(shù)據(jù)的獲取,數(shù)據(jù)的檢查,數(shù)據(jù)的展示。 包和類的單一定義包之前,需要先想好它的職責(zé)是什么,明確定義并確保它只有一個職責(zé)。例如,com.keegan.activity,就是activity類的包,不會有其他組件;com.keegan.adapter,就是存放各種適配器的包;com.keegan.util就是工具包了。同樣,類的定義,也是需要明確它的單一職責(zé)。有些人習(xí)慣將adapter寫在Activity里,因為覺得這個adapter只在這個Activity里用到,沒必要再把它獨立出來。以前的我也是這么干的,這么做了一段時間之后,覺得實在糟糕透了,重復(fù)的代碼無法復(fù)用,界面上的一點小需求調(diào)整時,很多代碼需要跟著調(diào)整。后來,進(jìn)行了一番重構(gòu),將所有adapter獨立了出來,并抽象出了一個adapter的基類,自此,當(dāng)需要再添加adapter時,編寫的代碼量大大減少了,當(dāng)界面需求調(diào)整時,修改的地方也大大減少了。所以,不要讓一個類做太多事情,要分離好各種元素,每個元素只做一件簡單的事。 方法的單一方法的單一,表現(xiàn)為一個方法是對一個行為的封裝。然而,一個行為又可以拆分為多個步驟,每個步驟其實也是一個更細(xì)的行為,又可以封裝成一個新的方法。因此,方法嵌套方法是一種常態(tài)。那么,保持方法的單一性,關(guān)鍵并不在于怎么定義這個方法的行為,而在于這個行為要怎么拆分成更細(xì)的行為。舉個例子,通常在Activity的onCreate方法,做數(shù)據(jù)的初始化,細(xì)分出來就分為了:控件的初始化、邏輯變量的初始化、數(shù)據(jù)的加載和展示。數(shù)據(jù)的加載和展示可以再細(xì)分:從緩存加載數(shù)據(jù)、從網(wǎng)絡(luò)加載數(shù)據(jù)、展示數(shù)據(jù)。每個細(xì)化的行為都應(yīng)該封裝為一個獨立的方法,這樣,才真正符合方法的單一性。 資源文件的單一Android提供了各種資源文件,strings.xml用來存儲字符串,arrays.xml用來存儲字符串?dāng)?shù)組,colors.xml用來存儲顏色值,dimens.xml用來存儲尺寸值,等等。資源文件的單一,是說所有相關(guān)的資源信息要在資源文件里定義并引用到代碼或布局文件里,而不是在代碼或布局文件里直接定義。很多開發(fā)人員,為了圖方便,應(yīng)用界面中出現(xiàn)的字符串經(jīng)常在代碼或布局文件里直接定義的,尺寸值也是,這樣造成的結(jié)果就是,當(dāng)某些字符串需要修改時,比如要支持國際化,或一些尺寸值需要修改時,通常是很多地方都要修改。因此,就必須規(guī)范好,應(yīng)用界面中的字符串統(tǒng)一在strings.xml中定義,顏色值統(tǒng)一在colors.xml中定義,尺寸值統(tǒng)一在dimens.xml中定義,代碼或布局里需要用到的都去引用資源文件相應(yīng)的字段。
要保持單一性,必定伴隨著重構(gòu)。需求總會變動,代碼總會擴(kuò)展,擴(kuò)展了慢慢就會破壞原有的單一性,因此就需要重構(gòu),再次保持單一性。不斷擴(kuò)展,不斷重構(gòu),這樣才能不斷保持良好的單一性。 簡潔性
代碼最怕的就是臃腫,臃腫的代碼可讀性差,維護(hù)麻煩,擴(kuò)展更不用說了。沒有人會喜歡看臃腫的代碼,去維護(hù)更痛苦。我看到臃腫的代碼,都恨不得即刻進(jìn)行重構(gòu)。讓代碼保持簡潔,會讓人看得舒服,一目了然,維護(hù)和擴(kuò)展起來也都非常方便。簡潔的代碼,甚至不需要寫注釋,只從代碼就能讓人一眼看懂其做了什么。簡潔也并不只表現(xiàn)在代碼上,類、包、資源文件等的命名和組織結(jié)構(gòu)等也同樣需要保持簡潔。 如何保持簡潔?這個問題并沒有一個標(biāo)準(zhǔn)的答案,但有一個判斷是否簡潔的簡單標(biāo)準(zhǔn),那就是:直接閱讀代碼就能夠理解代碼的意圖,如果意圖不夠明顯,那就說明這段代碼還不夠簡潔。類、包、資源文件等等,也是同樣的評判標(biāo)準(zhǔn)。下面是我覺得對保持簡潔有一定作用的一些操作方法。 包的組織按照組件類型來分包,而不是按業(yè)務(wù)模塊來分包。業(yè)務(wù)有可能會變,但組件類型是基本不變的。另外,新加入的開發(fā)人員,對業(yè)務(wù)不熟悉,但對組件是很清楚的,理解快,入手也快。 類和接口的命名組件類的命名添加該組件的后綴,例如:Activity類命名添加Activity后綴,F(xiàn)ragment類命令添加Fragment后綴,適配器添加Adapter后綴,等等。實體類則可添加BO的后綴名稱,工具類添加util后綴,接口的實現(xiàn)類添加Impl的后綴。接口的命名也一樣,比如,我的項目中,接口層的接口后綴都帶上了Api,核心層的接口后綴都帶Action。 資源文件的分類strings.xml文件用來存儲應(yīng)用中的所有字符串,包括頁面標(biāo)題,按鈕文字,標(biāo)簽文字,提示文字等等,應(yīng)該做好分類并統(tǒng)一存放。下面是我推薦的分類方法,如果某個分類的字符串?dāng)?shù)量太多了,還可以拆分出來放到一個獨立的文件,比如頁面標(biāo)題,可以拆分到strings_title.xml文件里,其他資源文件也可以用類似的方式進(jìn)行處理: 頁面標(biāo)題,命名格式為:title_{頁面} 按鈕文字,命名格式為:btn_{按鈕事件} 標(biāo)簽文字,命名格式為:label_{標(biāo)簽文字} 選項卡文字,命名格式為:tab_{選項卡文字} 消息框文字,命名格式為:toast_{消息} 編輯框的提示文字,命名格式為:hint_{提示信息} 圖片的描述文字,命名格式為:desc_{圖片文字} 對話框的文字,命名格式為:dialog_{文字}
總結(jié)
規(guī)范性、單一性、簡潔性,這三個基本原則是相輔相成的。單一性和簡潔性是規(guī)范定義的標(biāo)準(zhǔn),不能脫離這兩個原則去定義規(guī)范。而對規(guī)范的嚴(yán)格執(zhí)行,則保證了后兩個原則的有效性。
嘮叨了這么多,還沒講到具體的實現(xiàn),下一次就說說實現(xiàn)篇吧。
|