Summary: 在一系列布爾表達式中,某個變量帶有「控制標記」(control flag)的做用。以break語句或return語句取代控制標記。java
動機:編程
在一系列條件表達式中,你經常會看到用以判斷什麼時候中止條件檢查的控制標記:編程語言
Set done to false函數
While not doneoop
If(condition)測試
Do something編碼
Set done to truespa
Next step of loopcode
這樣的控制標記帶來的麻煩超過了它所帶來的便利。人們之因此會使用這樣的控制標記,由於結構化編程原則告訴他們:每一個子程序只能有一個入口和一個出口。我贊同「單一入口」原則(並且現代編程語言也強迫咱們這樣作),可是「單一出口」原則會讓你在代碼中加入討厭的控制標記,大大下降條件表達式的可讀性。這就是編程語言提供break語句和continue語句的緣由:用它們跳出複雜的條件語句。去掉控制標記所產生的效果每每讓你大吃一驚:條件語句真正的用途會清晰得多。it
作法:
對控制標記的處理,最顯而易見的辦法就是使用Java提供的break語句或continue語句。
1.找出讓你跳出這段邏輯的控制標記值。
2.找出對標記變量賦值的語句,代以恰當的break語句或 continue語句。
3.每次替換後,編譯並測試。
在未能提供break和continue語句的編程語言中,可使用下述辦法。
1.運用Extract Method,將整段邏輯提煉到一個獨立函數中。
2.找出讓你跳出這段邏輯的控制標記值。
3.找出對標記變量賦值的語句,代以恰當的return語句。
4.每次替換後,編譯並測試。
即便在支持break和continue語句的編程語言中,咱們也優先考慮上述第二方案。由於return語句能夠很是清楚地表示:再也不執行該函數中的其餘任何代碼。若是還有這一類代碼,你遲早須要將這段代碼提煉出來。
請注意標記變量是否會影響這段邏輯的最後結果。若是有影響,使用break語句以後還得保留控制標記值。若是你已經將這段邏輯提煉成一個獨立函數,也能夠將控制標記值放在return語句中返回。
範例1: 以break 取代簡單的控制標記
下列函數用來檢查一系列人名之中是否包含兩個可疑人物的名字(這兩我的的名字硬編碼與代碼中):
void checkSecuurity(String[] people){ boolean found = false; for(int i=0; i < people.length; i++){ if(!found){ if(people[i].equals("Don")){ sendAlert(); found = true; } if(people[i].equals("John")){ sendAlert(); found = true; } } } }
這種狀況下很容易找出控制標記:當變量found被賦予true時,搜索就結束。咱們能夠逐一引入break語句,直到替換掉全部found變量語句:
void checkSecuurity(String[] people){ boolean found = false; for(int i=0; i < people.length; i++){ if(!found){ if(people[i].equals("Don")){ sendAlert(); break; } if(people[i].equals("John")){ sendAlert(); break; } } } }
而後就能夠把全部對控制標記的引用都去掉:
void checkSecuurity(String[] people){ for(int i=0; i < people.length; i++){ if(people[i].equals("Don")){ sendAlert(); break; } if(people[i].equals("John")){ sendAlert(); break; } } }
範例2:以return 返回控制標記
本項重構的另外一種形式將使用return語句。爲了闡述這種方法,咱們把前面的例子稍加修改,以控制標記記錄搜索結果:
void checkSecuurity(String[] people){ String found = ""; for(int i=0; i < people.length; i++){ if(found.equals("")){ if(people[i].equals("Don")){ sendAlert(); found = "Don"; } if(people[i].equals("John")){ sendAlert(); found = "John"; } } } someLaterCode(found); }
在這裏變量found作了兩件事:它既是控制標記,也是運算結果。遇到這種狀況,咱們先把計算found變量的代碼提煉到一個獨立函數中:
void checkSecurity(String[] people){ String found = foundMiscreant(people); someLaterCode(found); } String foundMiscreant(String[] people){ String found = ""; for(int i=0; i < people.length; i++){ if(found.equals("")){ if(people[i].equals("Don")){ sendAlert(); found = "Don"; } if(people[i].equals("John")){ sendAlert(); found = "John"; } } } return found; }
而後以return語句取代控制標記:
String foundMiscreant(String[] people){ String found = ""; for(int i=0; i < people.length; i++){ if(found.equals("")){ if(people[i].equals("Don")){ sendAlert(); return "Don"; } if(people[i].equals("John")){ sendAlert(); return "John"; } } } return found; }
最後徹底去掉控制標記:
String foundMiscreant(String[] people){ for(int i=0; i < people.length; i++){ if(found.equals("")){ if(people[i].equals("Don")){ sendAlert(); return "Don"; } if(people[i].equals("John")){ sendAlert(); return "John"; } } } return ""; }
即便不須要返回某值,也能夠用return語句來取代控制標記。這時候你只須要一個空的return語句就好了。
固然,若是以此辦法去處理帶有反作用的函數,會有一些問題。因此咱們須要先以Separate Query from Modifier將函數反作用分離出去。