最近筆者看到了一篇文章介紹javascript如何寫出更好的條件判斷,發現其中的用法,自己一路走來也不自覺都用上了,這些方式並不侷限於javascript,本篇就用C#來示範,不僅讓可讀性變高,自己看起來也更順眼了。
用陣列是否包含取代逐一判斷
某次需要權限判斷時,因為系統不複雜,所以身分和權限是用常數定義在程式內,為了凸顯用陣列的好處,先用瑣碎的方式來判斷:
const int ADMIN = 1;
const int MANAGER = 2;
const int USER = 3;
const int ACTION_1 = 1;
const int ACTION_2 = 2;
const int ACTION_3 = 3;
const int ACTION_4 = 4;
const int ACTION_5 = 5;
const int ACTION_6 = 6;
//依據身分判斷動作是否允許
//原始作法,個別判斷
if(permission == USER){
if(action == ACTION_4 || action == ACTION_5 || action == ACTION_6){
//允許執行動作
}
}
這方式用起來很瑣碎,要新增允許的動作時,也很難維護,改寫成陣列方式試試
//先將各身分的動作定義好
int[] ADMIN_ACTIONS = new int[]{ ACTION_1, ACTION_2, ACTION_3, ACTION_4, ACTION_5, ACTION_6 };
int[] MANAGER_ACTIONS = new int[]{ ACTION_2, ACTION_3, ACTION_4, ACTION_5, ACTION_6 };
int[] USER_ACTIONS = new int[]{ ACTION_4, ACTION_5, ACTION_6 };
//直接使用陣列方法是否包含
if(permission == USER && USER_ACTIONS.Contains(action)){
//允許執行動作
}
修改後相對簡便許多,日後增加動作直接添加在陣列內就好了
用map取代switch
承上例,可以再進一步改進,連身分也不需要判斷,如果高權限包含低權限,可以進一步優化
//各身分的動作可以向前包含,並且增減不需要額外修改
int[] USER_ACTIONS = new int[] { ACTION_4, ACTION_5, ACTION_6 };
int[] MANAGER_ACTIONS = USER_ACTIONS.Concat(new int[] { ACTION_2, ACTION_3 }).ToArray();
int[] ADMIN_ACTIONS = MANAGER_ACTIONS.Concat(new int[] { ACTION_1 }).ToArray();
Dictionary<int, int[]> PERMISSION = new Dictionary<int, int[]>() {
{ ADMIN, ADMIN_ACTIONS },
{ MANAGER, MANAGER_ACTIONS },
{ USER, USER_ACTIONS },
};
if (PERMISSION[permission].Contains(action)) {
//允許執行動作
}
和一開始的例子做比較,可讀性和可維護性都大大提升了許多,當初能想到這樣改良,其實也是一個習慣,當你在做重複的動作時,就代表那些動作可以找出規律統整起來,多花點心思,就可以改善許多。
提早return,減少分支
在多層if判斷時,會長出許多if else,太多層時就難以讀取或維護,萬一未來更改條件時,改錯層,就埋下bug了
public string function HaveAdminPermission(){
if(has_login){
if(permission == ADMIN){
if(action == ACTION_1){
return "允許執行動作";
}else{
return "wrong action";
}
}else{
return "not admin";
}
}else{
return "not login";
}
}
上方的例子,看起來像千層麵一樣,如果可以減少層數,那接手的人或者未來自己失憶時也比較快理解
public string function HaveAdminPermission(){
if(!has_login){ return "not login"; }
if(permission != ADMIN){ return "not admin"; }
if(action != ACTION_1){ reutrn "wrong action"; }
return "允許執行動作";
}
如此少了許多層的else,條件看起來清晰易懂,簡化成一層,維護性大提升~
判斷全部符合或部分符合
以往這類型的判斷,都是要使用迴圈,但C#的LINQ大大簡化了這部分
class Book
{
public string Name { get; set; }
public string Type { get; set; }
}
var array = new Book[] {
new Book(){Name = "a", Type = "novel"},
new Book(){Name = "b", Type = "novel"},
new Book(){Name = "c", Type = "novel"}
};
//是否包含名稱b
bool have_b = false;
for(var item in array){
if(item.Name == "b"){
have_b = true;
break;
}
}
//是否全部類型都是novel
var all_is_novel = true;
for(var item in array){
if(item.Type != "novel"){
all_is_novel = false;
}
}
//改用LINQ判斷
have_b = array.Any(x => x.Name == "b");//True
all_is_novel = array.All(x => x.Type == "novel");//True
不得不說,現在寫C#,不用LINQ渾身不對勁,畢竟太方便了,一行搞定以前需要好幾行的事,但是要注意別走火入魔,真的沒法簡化的,或是破壞可讀性的,還是用傳統方式好。
null條件運算子
有時候null的判斷,真心煩人,不判斷又會有exception,但每次判斷又覺得做重複的事,這事早已經在C# 6.0之後被解決了,是不是很方便呢~
Book book = null;
string name = null;
if(book != null && book.Name != null){
name = book.Name;
}
else{
name = string.Empty;
}
//簡化取值的判斷
name = book?.Name;//null
//簡化預設值的設置,若是null則為string.Empty
name = book?.Name ?? string.Empty;
參考
發表迴響