Why ?
合法性檢查對於程序的健壯性具有重要作用。在Android開發中,良好的合法性檢查設計機制可以使程序更加清晰,產生bug更少,交互更加友好。
What ?
合法性檢查的目的在於確定邊界。對於在程序中流動的數據來說,其流動路徑往往是很復雜的。為了保證程序的健壯性,需要保證數據從一端流入並且從另外一端流出的過程中不會發生異常行為。數據流經的每一個方法都必須保證異常被正確處理。為了讓每一個函數清晰簡單,有必要在數據進入函數之前保證其合法性。讓函數中的邏輯不受數據邊界的影響。
Who ?
接受合法性檢查的對象一般是某一事件觸發后需要的初始數據,大多以函數參數形式進行調用。對於Android開發來說。最頻繁需要進行檢查的莫過於EditText組件。該組件接受用戶的輸入,是很多功能的數據來源。網絡請求的返回數據也是很重要的數據來源。正確處理這些初始的數據,保證其合法性,使得之后的程序邏輯不再受數據異常的影響,同時給予用戶一個良好的交互反饋是必須要做的。
When
合法性檢查發生在數據中轉的入口(也可能是運行的開始)。
How
合法性檢查需要從以下幾方面着手
- 安全的類型轉換工廠
由於程序的數據來源是很復雜的,數據往往需要進行加工和各種數據轉換。雖然JAVA提供了許多數據轉換的方法。但是,直接在功能代碼中使用這些方法是不明智的。很可能產生異常,而當程序沒有適當的捕捉和處理異常時,就有可能發生程序崩潰。安全的做法是建立一個安全的類型轉換工廠,統一處理需要進行類型轉換的數據。
舉例:
假設用戶輸入兩個數字,程序需要將兩個數字加起來。直接進行類型轉換是不安全的。
bad practice :
Double plus(String inputA, String inputB) {
return Double.valueOf(inputA) + Double.valueOf(inputB);
}
good practice:
private Integer plus(String inputA, String inputB){
Integer convertA = StringConverter.getInteger(inputA) ;
Integer convertB = StringConverter.getInteger(inputB) ;
if(convertA != null && convertB != null) {
return convertA + convertB;
}else {
//null must be handled to avoid NullPointerException
return null;
}
}
public class StringConverter {
public static Integer getIntegerValue(String var) {
try{
return Integer.valueOf(var);
}catch(Exception e) {
//ignore much code of print exception and other options
return null;
}
}
}
- 安全的構造函數
在構造函數中檢查初始化參數是一個很好的習慣,可以防止不恰當的初始化發生。
舉例:
public class Age {
int age;
public Age(int age) throws AgeNegativeException {
if(age == null || age < 0) {
//age can never be a negative number or null
throw(new AgeNegativeException());
}else {
this.age = age;
}
public int getAge() { return age;}
}
public class AgeNegativeException extends Exception {
//exception definition details ignored
}
- 分層清晰的異常處理機制
異常有可能發生在入口處,也有可能發生在運行時。數據流經的地方,都需要確定自己的邊界。每一個函數都應該明確自己的責任。對於整個程序結構來說。針對各個不同的模塊需要定義相關的異常並且在相應的層面上去處理異常。
舉例:
結合上面兩個例子,用戶需要做一個年齡累加統計。每次輸入兩個需要累加的年齡,返回累加后的年齡。
public Age addAge(String inputA, String inputB) throws AgeNegativeException {
//calculate and return
return new Age(plus(inputA, inputB));
}
example1:
inputA = “dhkja”; inputB = "10";
如果用戶輸入了這兩個值。那么
plus(inputA, inputB)
會返回一個null。在構造Age的時候就會拋出異常。由於這個異常是用戶輸入不當造成的因此需要將異常再次拋出到Activity那一層,讓Activity提示用戶輸入有誤。
- 為每一個文本框設置校驗
為文本框設置校驗涉及到兩方面
1、校驗時間
2、校驗提示
校驗時間:
- 用戶輸入前
- 用戶輸入時
- 失去焦點時
- 用戶觸發相關方法時
前三種可以通過設置文本監聽進行處理,最后一種屬於事后檢驗不設置文本監聽。
校驗提示:
- 彈出框形式
- ErrorMessage
彈出框可以彈出Toast或者一個dialog,ErrorMessage可以通過設置EditText 的ErrorMessage實現。也可以借助開源組件實現。例如android-edittext-validator
經過如此設計,就不太會受到數據異常的困擾了。關於文本監聽和校驗提示,會在另外文章說明。
