返回總目錄 本小節目錄 Consolidate Duplicate Conditional Fragments(合併重覆的條件片段) Remove Control Flag(移除控制標記) 3Consolidate Duplicate Conditional Fragments(合併重覆的條件片段) ...
本小節目錄
3Consolidate Duplicate Conditional Fragments(合併重覆的條件片段)
概要
在條件表達式的每個分支上有著相同的一段代碼。
將這段重覆代碼搬到條件表達式之外。
動機
如果有一組條件表達式的所有分支都執行了相同的某段代碼,將這段代碼搬移到條件表達式外面。這樣才能更清楚地表明哪些東西隨條件的變化而變化、哪些東西保持不變。
範例
假如有如下代碼:
class Deal { public double Price { get; set; } private bool IsSpecialDeal() { //your code here return true; } private void Send() { //your code here } public double GetTotalPrice() { double total; if (IsSpecialDeal()) { total = Price * 0.95; Send(); } else { total = Price * 0.98; Send(); } return total; } }
由於條件表達式的兩個分支都執行了Send()函數,所以將其移到條件表達式的外圍:
class Deal { public double Price { get; set; } private bool IsSpecialDeal() { //your code here return true; } private void Send() { //your code here } public double GetTotalPrice() { double total; if (IsSpecialDeal()) { total = Price * 0.95; } else { total = Price * 0.98; } Send(); return total; } }
這樣的重構手法同時也可以避免重覆代碼。
小結
我們在對待異常時,也是這樣做的。如果try塊和catch塊內都重覆執行了同一段代碼,可以將其移到finally塊內。
4Remove Control Flag(移除控制標記)
概要
在一系列布爾表達式中,某個變數帶著“控制標記”(control flag)的作用。
以break語句或return語句取代控制標記。
動機
在一系列條件表達式中,常常會看到用以判斷何時停止條件檢查的控制標記:
set done to false
while not done
if(condition)
do something
set done to true
next step of loop
這樣的控制標記大大降低了條件表達式的可讀性。以break語句或return語句取代控制標記,會帶來很大的便利。
範例:以break取代簡單的控制標記
下列函數用來檢查一系列人名之中是否包含兩個可疑人物的名字:
class Person { public void CheckSecurity(string[] people) { bool found = false; foreach (var person in people) { if (!found) { if (person == "Don") { SendAlert(); found = true; } if (person == "John") { SendAlert(); found = true; } } } } private void SendAlert() { } }
這種情況下很容易找出控制標記:當變數found被賦予true時,搜索就結束。這樣我們可以引入break語句替換掉對found變數賦值的語句,替換完成後刪除控制標記的引用:
class Person { public void CheckSecurity(string[] people) { foreach (var person in people) { if (person == "Don") { SendAlert(); break; } if (person == "John") { SendAlert(); break; } } } private void SendAlert() { } }
範例:以return返回控制標記
我們將上面的例子稍微改動下:
class Person { public void CheckSecurity(string[] people) { string found = string.Empty; foreach (var person in people) { if (found == string.Empty) { if (person == "Don") { SendAlert(); found = "Don"; } if (person == "John") { SendAlert(); found = "John"; } } } OtherMethod(found); } private void SendAlert() { } private void OtherMethod(string found) { } }
在這裡,變數found做了兩件事:既是控制標記,也是運算結果。遇到這種情況,一般都是先把計算found變數的代碼提煉到一個獨立函數中:
class Person { public void CheckSecurity(string[] people) { string found = FoundMiscreant(people); OtherMethod(found); } private string FoundMiscreant(string[] people) { string found = string.Empty; foreach (var person in people) { if (person == "Don") { SendAlert(); found = "Don"; } if (person == "John") { SendAlert(); found = "John"; } } return found; } private void SendAlert() { } private void OtherMethod(string found) { } }
然後以return語句取代控制語句,並且完全去掉控制標記:
class Person { public void CheckSecurity(string[] people) { string found = FoundMiscreant(people); OtherMethod(found); } private string FoundMiscreant(string[] people) { foreach (var person in people) { if (person == "Don") { SendAlert(); return "Don"; } if (person == "John") { SendAlert(); return "John"; } } return string.Empty; } private void SendAlert() { } private void OtherMethod(string found) { } }
如果返回值是void,也可以用return語句取代控制標記,只不過是一個空的return。
小結
如果以此辦法去處理帶有副作用的函數,需要先將查詢函數和修改函數分離。
To Be Continued……