https://jeroenmols.com/blog/2016/03/07/resourcenaming/
書寫規范
1. 編碼方式統一用UTF-8. Android Studio默認已是UTF-8,只要不去改動它就可以了。
2. 縮進統一為4個空格,將Tab size設置為4則可以保證tab鍵按4個空格縮進。另外,不要勾選上Use tab character,可以保證切換到不同tab長度的環境時還能繼續保持統一的4個空格的縮進樣式。
3. 花括號不要單獨一行,和它前面的代碼同一行。而且,花括號與前面的代碼之間用一個空格隔開。
public void method() { // Good
}
public void method()
{ // Bad
}
public void method(){ // Bad
}
4. 空格的使用
if、else、for、switch、while等邏輯關鍵字與后面的語句留一個空格隔開。
// Good
if (booleanVariable) {
// TODO while booleanVariable is true
} else {
// TODO else
}
// Bad
if(booleanVariable) {
// TODO while booleanVariable is true
}else {
// TODO else
}
運算符兩邊各用一個空格隔開。
int result = a + b; //Good, = 和 + 兩邊各用一個空格隔開
int result=a+b; //Bad,=和+兩邊沒用空格隔開
方法的每個參數之間用一個空格隔開。
public void method(String param1, String param2); // Good,param1后面的逗號與String之間隔了一個空格
method(param1, param2); // Good,方法調用時,param1后面的逗號與param2之間隔了一個空格
method(param1,param2); // Bad,沒有用一個空格隔開
5. 空行的使用
將邏輯相關的代碼段用空行隔開,以提高可讀性。空行也只空一行,不要空多行。在以下情況需用一個空行:
兩個方法之間
方法內的兩個邏輯段之間
方法內的局部變量和方法的第一條邏輯語句之間
常量和變量之間
6. 當一個表達式無法容納在一行內時,可換行顯示,另起的新行用8個空格縮進。
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
7. 一行聲明一個變量,不要一行聲明多個變量,這樣有利于寫注釋。
private String param1; // 參數1
private String param2; // 參數2
8. 行寬設置為100,設置格式化時自動斷行到行寬位置。
9. 使用快捷鍵進行代碼自動格式化。
Windows:CTRL+ALT+L
Mac:OPTION+COMMAND+L
10. 一個方法最多不要超過40行代碼。
11. 范圍型的常量用枚舉類定義,而不要直接用整型或字符,這樣可以減少范圍值的有效性檢查。
// 用枚舉類定義,Good
public enum CouponType {
// 現金券
@SerializedName("1")
CASH,
// 抵用券
@SerializedName("2")
DEBIT,
// 折扣券
@SerializedName("3")
DISCOUNT
}
// 用整型定義,Bad
public static final int TYPE_CASH = 1; // 現金券
public static final int TYPE_DEBIT = 2; // 抵扣券
public static final int TYPE_DISCOUNT = 3; // 折扣券
12. 文字大小的單位統一用sp,元素大小的單位統一用dp。(我們項目文字還是沿用dp)
13. 應用中的字符串統一在strings.xml中定義,然后在代碼和布局文件中引用。
14. 顏色值統一在colors.xml中定義,然后在代碼和布局文件中引用。另外,不要在代碼和布局文件中引用系統的顏色,除了透明。
命名規范
1. 包命名
域名反寫+項目名稱+模塊名稱,全部單詞用小寫字母。例如,V視角項目的Model模塊包名如下:
com.vpgame.eric.vperspectives.model
2. 類和接口命名
使用大駝峰規則,用名詞或名詞詞組命名,每個單詞的首字母大寫。以下為幾種常用類的命名:
- activity類,命名以Activity為后綴,如:LoginActivity
- fragment類,命名以Fragment為后綴,如:ShareDialogFragment
- service類,命名以Service為后綴,如:DownloadService
- adapter類,命名以Adapter為后綴,如:CouponListAdapter
- 工具類,命名以Util為后綴,如:EncryptUtil
- 模型類,命名以BO為后綴,如:CouponBO
- 接口實現類,命名以Impl為后綴,如:ApiImpl
3. 方法命名
使用小駝峰規則,用動詞命名,第一個單詞的首字母小寫,其他單詞的首字母大寫。以下為幾種常用方法的命名:
- 初始化方法,命名以init開頭,例:initView
- 按鈕點擊方法,命名以to開頭,例:toLogin
- 設置方法,命名以set開頭,例:setData
- 具有返回值的獲取方法,命名以get開頭,例:getData
- 通過異步加載數據的方法,命名以load開頭,例:loadData
- 布爾型的判斷方法,命名以is或has,或具有邏輯意義的單詞如equals,例:isEmpty
4. 控件縮寫
控件 | 縮寫 | 控件 | 縮寫 |
---|---|---|---|
TextView | tv | EditText | edt |
Button | btn | ImageButton | ibtn |
ImageView | img | ListView | list |
RadioGroup | RadioButton | RadioButton | rbtn |
ProgressBar | ProgressBar | SeekBar | seek |
CheckBox | chk | Spinner | spinner |
TableLayout | tl | TableRow | trow |
LinearLayout | ll | RelativeLayout | rl |
ScrollView | sv | SearchView | search |
TabHost | th | TabWidget | tw |
5. 常量命名
全部為大寫單詞,單詞之間用下劃線分開。
public final static int PAGE_SIZE = 20;
6. 變量命名
{范圍描述+}意義描述+類型描述的組合,用駝峰式,首字母小寫。
private TextView tvHeaderTitle;
7. 控件id命名
控件縮寫{范圍}意義,范圍可選,只在有明確定義的范圍內才需要加上。
<!-- 這是標題欄的標題 -->
<TextView
android:id="@+id/tv_header_title"
... />
<!-- 這是登錄按鈕 -->
<Button
android:id="@+id/btn_login"
... />
8. layout命名
組件類型{范圍}功能,范圍可選,只在有明確定義的范圍內才需要加上。以下為幾種常用的組件類型命名:
- activity_{范圍_}功能,為Activity的命名格式
- fragment_{范圍_}功能,為Fragment的命名格式
- dialog_{范圍_}功能,為Dialog的命名格式
- item_{范圍_}功能,為列表的item命名格式
我們項目是組件化開發需要加上module類型前綴,舉例:
market_item__pro_deal.xml //module類型>market/組件類型>item/范圍>pro/功能>deal
9. strings的命名
類型{范圍}功能,范圍可選。以下為幾種常用的命名:
- 頁面標題,命名格式為:title_頁面
- 選項卡文字,命名格式為:tab_選項卡文字
- 消息框文字,命名格式為:toast_消息
- 編輯框的提示文字,命名格式為:hint_提示信息
- 圖片的描述文字,命名格式為:desc_圖片文字
- 對話框的文字,命名格式為:dialog_文字
- menu的item文字,命名格式為:action_文字
- 提示文字,命名格式為:tips_文字
10. colors的命名
前綴{控件}{范圍}{_后綴},控件、范圍、后綴可選,但控件和范圍至少要有一個。
- 背景顏色,添加bg前綴
- 文本顏色,添加text前綴
- 分割線顏色,添加div前綴
- 區分狀態時,默認狀態的顏色,添加normal后綴
- 區分狀態時,按下時的顏色,添加pressed后綴
- 區分狀態時,選中時的顏色,添加selected后綴
- 區分狀態時,不可用時的顏色,添加disable后綴
- 多種狀態的,添加selector后綴
11. drawable的命名
全部小寫,采用下劃線命名法,加前綴區分
命名模式:可加后綴 _small 表示小圖, _big 表示大圖,邏輯名稱可由多個單詞加下劃線組成,采用以下規則:
- 用途模塊名邏輯名稱
- 用途模塊名顏色
- 用途_邏輯名稱
- 用途_顏色
說明:用途也指控件類型(具體見UI控件縮寫表) - 圖標類,添加ic前綴
- 背景類,添加bg前綴
- 分隔類,添加div前綴
- 默認類,添加def前綴
- 區分狀態時,默認狀態,添加normal后綴
- 區分狀態時,按下時的狀態,添加pressed后綴
- 區分狀態時,選中時的狀態,添加selected后綴
- 區分狀態時,不可用時的狀態,添加disable后綴
- 多種狀態的,添加selector后綴(一般為ListView的selector或按鈕的selector)
- shape文件,顏色或者圓角的,添加后綴
例如:
btn_main_home.png //按鍵
divider_maket_white.png //分割線
ic_edit.png //圖標
bg_main.png //背景
btn_red.png //紅色按鍵
btn_red_big.png //紅色大按鍵
ic_head_small.png //小頭像
bg_input.png //輸入框背景
divider_white.png// 白色分割線
12. 動畫文件命名
動畫類型_動畫方向。
- fade_in,淡入
- fade_out,淡出
- push_down_in,從下方推入
- push_down_out,從下方推出
- slide_in_from_top,從頭部滑動進入
- zoom_enter,變形進入
- shrink_to_middle,中間縮小
注釋規范
1. 文件頭注釋
文件頂部統一添加版權聲明,聲明的格式如下:
/** * Copyright (c) 2017. vpgame. All rights reserved. */
2. 類和接口注釋
類和接口統一添加javadoc注釋,格式如下:
*
* @Description: $desc$
* @author: $user$
* @data: $date$ $time$
* @version: 1.0
*/
3. 方法注釋
下面幾種方法,都必須添加javadoc注釋,說明該方法的用途和參數說明,以及返回值的說明。
- 接口中定義的所有方法
- 抽象類中自定義的抽象方法
- 抽象父類的自定義公用方法
- 工具類的公用方法
/**
* 登錄
*
* @param loginName 登錄名
* @param password 密碼
* @param listener 回調監聽器
*/
public void login(String loginName, String password, ActionCallbackListener<Void> listener);
4. 變量和常量注釋
下面幾種情況下的常量和變量,都要添加注釋說明,優先采用右側//來注釋,若注釋說明太長則在上方添加注釋。
- 接口中定義的所有常量
- 公有類的公有常量
- 枚舉類定義的所有枚舉常量
- 實體類的屬性變量
public static final int TYPE_CASH = 1; // 現金券
public static final int TYPE_DEBIT = 2; // 抵扣券
public static final int TYPE_DISCOUNT = 3; // 折扣券
private int id; // 券id
private String name; // 券名稱
private String introduce; // 券簡介
5. 棄用注釋
棄用的方法,常量,類,都要用*@deprecated *注釋。例如:
分包
1.分包分析
按照功能分可能你不是很好區分在哪個功能中,不過也比你按照層區分要好找很多。
具體可以參考這篇博文~Package by features, not layers:
https://medium.com/@cesarmcferreira/package-by-features-not-layers-2d076df1964d#.mp782izhh
當然,我們大谷歌也有相應的sample~iosched
https://github.com/google/iosched/tree/master/android/src/main/java/com/google/samples/apps/iosched
其結構很值得學習
2.常見分包方式對比
PBF(按功能分包Package By Feature)與PBL(按層分包Package By Layer)相比較有如下優勢:
package內高內聚,package間低耦合
哪塊要添新功能,只改某一個package下的東西;
按class職能分層(PBL)降低了代碼耦合,但帶來了package耦合,要添新功能,需要改model、dbHelper、view、service等等,需要改動好幾個package下的代碼,改動的地方越多,越容易產生新問題,不是嗎?
按功能分包(PBF),featureA相關的所有東西都在featureA包,feature內高內聚高度模塊化,不同feature之間低耦合,相關的東西都放在一起,還好找
package有私有作用域(package-private scope)
你負責開發這塊功能,這個目錄下所有東西都是你的;
PBL的方式是把所有工具方法都放在util包下,小張開發新功能時候發現需要一個xxUtil,但它又不是通用的,那應該放在哪里?
沒辦法,按照分層原則,我們還得放在util包下,好像不太合適,但放在其它包更不合適,功能越來越多,util類也越定義越多。后來小李負責開發一塊功能時發現需要一個xxUtil,同樣不通用,去util包一看,怎么已經有了,而且還沒法復用,只好放棄xx這個名字,改為xxxUtil……因為PBL的package沒有私有作用域,每一個包都是public(跨包方法調用是很平常的事情,每一個包對其它包來說都是可訪問的)
如果是PBF,小張的xxUtil自然放在feautreA下,小李的xxUtil在featureB下,如果覺得util好像是通用的,就去util包看看要不要把工具方法添進xxUtil,class命名沖突沒有了;
PBF的package有私有作用域,featureA不應該訪問featureB下的任何東西(如果非訪問不可,那就說明接口定義有問題)
很容易刪除功能
統計發現新功能沒人用,這個版本那塊功能得去掉
如果是PBL,得從功能入口到整個業務流程把受到牽連的所有能刪的代碼和class都揪出來刪掉,一不小心就完蛋;
如果是PBF,好說,先刪掉對應包,再刪掉功能入口(刪掉包后入口肯定報錯了),完事。
高度抽象
解決問題的一般方法是從抽象到具體,PBF包名是對功能模塊的抽象,包內的class是實現細節,符合從抽象到具體,而PBL弄反了;
PBF從確定AppName開始,根據功能模塊劃分package,再考慮每塊的具體實現細節,而PBL從一開始就要考慮要不要dao層,要不要com層等等
只通過class來分離邏輯代碼
PBL既分離class又分離package,而PBF只通過class來分離邏輯代碼
沒有必要通過package分離,因為PBL中也可能出現尷尬的情況:
├─service
│MainServ.java
按照PBL,service包下的所有東西都是Controller,應該不需要Serv后綴,但實際上通常為了碼起來方便,直接import service包,Serv后綴是為了避免引入的class和當前包下的class命名沖突。
當然,不用后綴也可以,得寫清楚包路徑,比如new net.ayqy.service.Main(),麻煩;而PBF就很方便,無需import,直接new MainServ()即可。
package的大小有意義了
PBL中包的大小無限增長是合理的,因為功能越添越多;而PBF中包太大(包里class太多)表示這塊需要重構(劃分子包)。
結束語
這份開發規范說明比較細,也許還不是非常完整,也許有的不符合個人習慣,請大家求同存異,產出一份約束規范,并按照實施,將大大提高代碼的可讀性和維護性。