Android 專案重構之路:介面篇

發表於2015-11-19

Android專案重構之路:架構篇
Android專案重構之路:介面篇
Android專案重構之路:實現篇


在前一篇文章《Android專案重構之路:架構篇》中已經簡單說明了專案的架構,將專案分為了四個層級:模型層、介面層、核心層、介面層。其中,最上層的介面,是變化最頻繁的一個層面,也是最複雜最容易出問題的一個層面,如果規劃不好,很容易做著做著,又亂成一團了。

要規劃好介面層,至少應該遵循幾條基本的原則:

  1. 保持規範性:定義好開發規範,包括書寫規範、命名規範、註釋規範等,並按照規範嚴格執行;
  2. 保持單一性:佈局就只做佈局,內容就只做內容,各自分離好;每個方法、每個類,也只做一件事情;
  3. 保持簡潔性:保持程式碼和結構的簡潔,每個方法,每個類,每個包,每個檔案,都不要塞太多程式碼或資源,感覺多了就應該拆分。

規範性

每個人的編碼習慣和風格都不同,不說那些缺乏良好編碼習慣的開發人員,就連那些已經養成良好編碼習慣的人員,很多方面都會不同。比如縮排,有的喜歡4個空格,有的喜歡兩個空格;比如變數名,有的喜歡m開頭,例如mValue,有的喜歡直接就命名為value。如果不設定好規範,讓每個人都按照自己的習慣和風格去編碼,久了肯定亂,尤其當團隊中存在還沒養成良好編碼習慣的人員時,更容易亂。所謂無規矩不成方圓,若無規範,久必亂。定義好規範,才能統一風格,才可提高程式碼可讀性,同時也提高了維護性,還減低了引入bug的機會。

開發規範並沒有統一的標準,在這裡,我只是根據自己的經驗對一些點提供一點建議,僅供參考。

  • 縮排

    很多人都習慣用Tab縮排,不管是規範4個空格還是2個空格,統一設定好Tab縮排的size就好了,這樣就不用讓每個人都去敲空格。

  • 命名

    一個好的命名,一眼就可以從名字中看到它是幹嘛的,做什麼用,什麼型別等等。舉個id命名的例子,看到有些團隊喜歡將一些控制元件縮寫,比如TextView縮寫為tv,ListView縮寫為lv,這種縮寫倒是挺簡潔的,但是並不能一眼就能看出它是什麼,對於不熟悉的人來說,誰知道tv和lv是什麼啊,還不如用text和list更明確些。我喜歡的id命名結構為:控制元件_範圍_功能,例如:edit_login_password,這是一個登入頁的密碼輸入框。

  • 單位

    文字大小的單位應該統一用sp,其他元素用dp。因為這兩個單位是與裝置解析度無關的,能夠解決在不同解析度裝置上顯示效果不同的問題。另外,SDK裡面,對文字大小系統預設是用sp單位的,但其他元素單位預設卻不是dp,而是px的,同時也沒有提供dp的設定介面,所以,自己寫兩個dp和px轉換的方法是很有必要的。

最重要的並不在於規範怎麼定義,而是在於規範的嚴格執行。如果規範定義好了,但卻不遵守,那規範就等於形同虛設,因此,規範一旦設定,就要嚴格執行。

單一性

我們都知道,物件導向設計中,有一個基本原則就是單一職責原則,它規定一個類應該只有一個發生變化的原因。而這裡說的單一性,不只是規定類,也規定了方法、包,甚至到最大層面的分層架構。保持單一性是減低耦合度的關鍵標準,其目的就是各方面的解耦。架構上的分層就是最大層面的解耦,而方法上的單一就是最小層面的解耦了。

  • 介面的單一

    介面上的單一,首先是介面的佈局和介面的資料應該分離。這一點,Android已經用layout和Activity做好解耦了,我們只要確保用layout檔案排好佈局,在Activity展示資料就好了。另外,介面資料的獲取和展示也應該分離。很多開發團隊習慣將資料的獲取和展示都放在Activity或Fragment裡完成的,架構篇的讀者裡也有人反映了這個情況,請求介面、獲取資料、檢查資料、顯示資料更新UI,全都在介面上完成的。這樣子的話,當資料的獲取發生改變時,比如要新增快取,這時候介面就需要改動了,當資料的展示也需要修改時,比如某個控制元件要展示其他資料,介面也一樣需要改動,也就是說,介面上已經有兩個發生變化的原因,這就違反了單一職責原則。
    介面上的單一,就是要保持介面上每個維度都做好分離,從介面的佈局,到資料的獲取,資料的檢查,資料的展示。

  • 包和類的單一

    定義包之前,需要先想好它的職責是什麼,明確定義並確保它只有一個職責。例如,com.keegan.activity,就是activity類的包,不會有其他元件;com.keegan.adapter,就是存放各種介面卡的包;com.keegan.util就是工具包了。同樣,類的定義,也是需要明確它的單一職責。有些人習慣將adapter寫在Activity裡,因為覺得這個adapter只在這個Activity裡用到,沒必要再把它獨立出來。以前的我也是這麼幹的,這麼做了一段時間之後,覺得實在糟糕透了,重複的程式碼無法複用,介面上的一點小需求調整時,很多程式碼需要跟著調整。後來,進行了一番重構,將所有adapter獨立了出來,並抽象出了一個adapter的基類,自此,當需要再新增adapter時,編寫的程式碼量大大減少了,當介面需求調整時,修改的地方也大大減少了。所以,不要讓一個類做太多事情,要分離好各種元素,每個元素只做一件簡單的事。

  • 方法的單一

    方法的單一,表現為一個方法是對一個行為的封裝。然而,一個行為又可以拆分為多個步驟,每個步驟其實也是一個更細的行為,又可以封裝成一個新的方法。因此,方法巢狀方法是一種常態。那麼,保持方法的單一性,關鍵並不在於怎麼定義這個方法的行為,而在於這個行為要怎麼拆分成更細的行為。舉個例子,通常在Activity的onCreate方法,做資料的初始化,細分出來就分為了:控制元件的初始化、邏輯變數的初始化、資料的載入和展示。資料的載入和展示可以再細分:從快取載入資料、從網路載入資料、展示資料。每個細化的行為都應該封裝為一個獨立的方法,這樣,才真正符合方法的單一性。

  • 資原始檔的單一

    Android提供了各種資原始檔,strings.xml用來儲存字串,arrays.xml用來儲存字串陣列,colors.xml用來儲存顏色值,dimens.xml用來儲存尺寸值,等等。資原始檔的單一,是說所有相關的資源資訊要在資原始檔裡定義並引用到程式碼或佈局檔案裡,而不是在程式碼或佈局檔案裡直接定義。很多開發人員,為了圖方便,應用介面中出現的字串經常在程式碼或佈局檔案裡直接定義的,尺寸值也是,這樣造成的結果就是,當某些字串需要修改時,比如要支援國際化,或一些尺寸值需要修改時,通常是很多地方都要修改。因此,就必須規範好,應用介面中的字串統一在strings.xml中定義,顏色值統一在colors.xml中定義,尺寸值統一在dimens.xml中定義,程式碼或佈局裡需要用到的都去引用資原始檔相應的欄位。

要保持單一性,必定伴隨著重構。需求總會變動,程式碼總會擴充套件,擴充套件了慢慢就會破壞原有的單一性,因此就需要重構,再次保持單一性。不斷擴充套件,不斷重構,這樣才能不斷保持良好的單一性。

簡潔性

程式碼最怕的就是臃腫,臃腫的程式碼可讀性差,維護麻煩,擴充套件更不用說了。沒有人會喜歡看臃腫的程式碼,去維護更痛苦。我看到臃腫的程式碼,都恨不得即刻進行重構。讓程式碼保持簡潔,會讓人看得舒服,一目瞭然,維護和擴充套件起來也都非常方便。簡潔的程式碼,甚至不需要寫註釋,只從程式碼就能讓人一眼看懂其做了什麼。簡潔也並不只表現在程式碼上,類、包、資原始檔等的命名和組織結構等也同樣需要保持簡潔。

如何保持簡潔?這個問題並沒有一個標準的答案,但有一個判斷是否簡潔的簡單標準,那就是:直接閱讀程式碼就能夠理解程式碼的意圖,如果意圖不夠明顯,那就說明這段程式碼還不夠簡潔。類、包、資原始檔等等,也是同樣的評判標準。下面是我覺得對保持簡潔有一定作用的一些操作方法。

  • 包的組織

    按照元件型別來分包,而不是按業務模組來分包。業務有可能會變,但元件型別是基本不變的。另外,新加入的開發人員,對業務不熟悉,但對元件是很清楚的,理解快,入手也快。

  • 類和介面的命名

    元件類的命名新增該元件的字尾,例如:Activity類命名新增Activity字尾,Fragment類命令新增Fragment字尾,介面卡新增Adapter字尾,等等。實體類則可新增BO的字尾名稱,工具類新增util字尾,介面的實現類新增Impl的字尾。介面的命名也一樣,比如,我的專案中,介面層的介面字尾都帶上了Api,核心層的介面字尾都帶Action。

  • 資原始檔的分類

    strings.xml檔案用來儲存應用中的所有字串,包括頁面標題,按鈕文字,標籤文字,提示文字等等,應該做好分類並統一存放。下面是我推薦的分類方法,如果某個分類的字串數量太多了,還可以拆分出來放到一個獨立的檔案,比如頁面標題,可以拆分到strings_title.xml檔案裡,其他資原始檔也可以用類似的方式進行處理:

    • 頁面標題,命名格式為:title_{頁面}
    • 按鈕文字,命名格式為:btn_{按鈕事件}
    • 標籤文字,命名格式為:label_{標籤文字}
    • 選項卡文字,命名格式為:tab_{選項卡文字}
    • 訊息框文字,命名格式為:toast_{訊息}
    • 編輯框的提示文字,命名格式為:hint_{提示資訊}
    • 圖片的描述文字,命名格式為:desc_{圖片文字}
    • 對話方塊的文字,命名格式為:dialog_{文字}

總結

規範性、單一性、簡潔性,這三個基本原則是相輔相成的。單一性和簡潔性是規範定義的標準,不能脫離這兩個原則去定義規範。而對規範的嚴格執行,則保證了後兩個原則的有效性。


嘮叨了這麼多,還沒講到具體的實現,下一次就說說實現篇吧。

相關文章