那有什么天生如此,只是我們天天堅(jiān)持。
本篇文章主要講解 《重構(gòu)---改善既有代碼的設(shè)計(jì)》 這本書(shū)中的 第九章簡(jiǎn)化條件表達(dá)式中 的知識(shí)點(diǎn),
Decompose Conditional(分解條件表達(dá)式)問(wèn)題:你有一個(gè)復(fù)雜的條件(if、then、else) 語(yǔ)句
解決:從if、then、else三個(gè)段落中分別提煉出獨(dú)立函數(shù)
//重構(gòu)前 if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;
//重構(gòu)后 if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge(quantity);動(dòng)機(jī)
將條件分支的代碼分解成多個(gè)獨(dú)立函數(shù),根據(jù)每個(gè)小塊代碼的用途,為分解而得的新函數(shù)命名,并將原函數(shù)中對(duì)應(yīng)的代碼改為調(diào)用新建函數(shù),可以更清楚地表達(dá)自己的意圖。
做法將if段落提煉出來(lái),構(gòu)成一個(gè)獨(dú)立函數(shù)
將then段落和else段落都提煉出來(lái),各自構(gòu)成一個(gè)獨(dú)立函數(shù)
Consolidate Conditional Expression(合并條件表達(dá)式)問(wèn)題:如果有一系列條件測(cè)試,都得到相同結(jié)果。
解決:將這些測(cè)試合并為一個(gè)條件表達(dá)式,并將這個(gè)條件表達(dá)式提煉成為一個(gè)獨(dú)立函數(shù)
//重構(gòu)前 double disabilityAmount(){ if(_seniority < 2) return 0; if(_monthsDisabled > 12) return 0; if(_isPartTime) return 0; }
//重構(gòu)后 double disabilityAmount(){ if(isNotEligableForDisability()) return 0; }動(dòng)機(jī)
如果一串條件檢查:檢查條件各不相同,最終行為卻一致,就應(yīng)該將它們合并為一個(gè)條件表達(dá)式,之所以要合并條件代碼,有兩個(gè)重要原因,
首先,合并后的條件代碼用意更清晰,其次,這項(xiàng)重構(gòu)往往可以為使用Extract Method(提煉函數(shù))做好準(zhǔn)備
確定這些條件語(yǔ)句都沒(méi)有副作用
使用適當(dāng)?shù)倪壿嫴僮鞣瑢⒁幌盗邢嚓P(guān)條件表達(dá)式合并為一個(gè)
編譯,測(cè)試
對(duì)合并后的條件表達(dá)式實(shí)施Extract Method
Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片段)問(wèn)題:在條件表達(dá)式的每個(gè)分支上有著相同的一段代碼
解決:將這段重復(fù)代碼搬移到條件表達(dá)式之外
//重構(gòu)前 if(isSpecialDeal()){ total = price * 0.95; send(); } else{ total = price * 0.98; send(); }
//重構(gòu)后 if(isSpecialDeal()) total = price * 0.95; else total = price * 0.98; send();動(dòng)機(jī)
有助于清楚地表明哪些東西隨條件的變化而變化、哪些東西保持不變
做法鑒別出”執(zhí)行方式不隨條件變化而變化”的代碼‘
如果這些共通代碼位于條件表達(dá)式起始處,就將它移到條件表達(dá)式之前
如果這些共通代碼位于條件表達(dá)式尾端,就將它移到條件表達(dá)式之后
如果這些共通代碼位于條件表達(dá)式中段,就需要觀察共通代碼之前或之后的代碼是否改變了什么東西,如果的確有所改變,應(yīng)該首先將共通代碼向前或向后移動(dòng),移至條件表達(dá)式的起始處或尾端,再以前面所受的辦法來(lái)處理
如果共通代碼不止一條語(yǔ)句,應(yīng)該先使用Extract Method(提煉函數(shù))將共通代碼提煉到一個(gè)獨(dú)立函數(shù)中,再以前面所說(shuō)的辦法來(lái)處理
范例//重構(gòu)前 if (isSpecialDeal()) { total = price * 0.95; send(); } else { total = price * 0.98; send(); }
由于條件式的兩個(gè)分支都執(zhí)行了 send() 函數(shù),所以我應(yīng)該將send() 移到條件式的外圍:
if (isSpecialDeal()) total = price * 0.95; else total = price * 0.98; send();
我們也可以使用同樣的手法來(lái)對(duì)待異常(exceptions)。如果在try 區(qū)段內(nèi)「可能引發(fā)異?!沟恼Z(yǔ)句之后,以及所有catch 區(qū)段之內(nèi),都重復(fù)執(zhí)行了同一段代碼,我就 可以將這段重復(fù)代碼移到final 區(qū)段。
Remove Control Flag(移除控制標(biāo)記)問(wèn)題:在一系列布爾表達(dá)式中,某個(gè)變量帶有”控制標(biāo)記”的作用
解決:以break語(yǔ)句或return語(yǔ)句取代控制標(biāo)記
動(dòng)機(jī)在一系列條件表達(dá)式中,你常常會(huì)用到[用以何時(shí)停止條件檢查]的控制標(biāo)記。
set done to false while not done if (condition) //do something //set done to true next step of loop
用break語(yǔ)句和continue語(yǔ)句跳出復(fù)雜的條件語(yǔ)句
做法找出讓你跳出這段邏輯的控制標(biāo)記值
找出對(duì)標(biāo)記變量賦值的語(yǔ)句,代以恰當(dāng)?shù)腷reak語(yǔ)句或continue語(yǔ)句
每次替換后,編譯并測(cè)試
范例 :以break取代簡(jiǎn)單的控制標(biāo)記//重構(gòu)前 void checkSecurity(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; } } } }
=>
//重構(gòu)后 void checkSecurity(String[] people){ for(int i = 0; i < people.length; i++){ if(people[i].equals("Don")){ sendAlert(); break; } if(people[i].equals("John")){ sendAlert(); break; } } }范例 :以return返回控制標(biāo)記
//重構(gòu)前 void checkSecurity(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); }
//重構(gòu)后 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(); return "Don"; } if(people[i].equals("John")){ sendAlert(); return "John"; } } } return ""; }Replace Nested Conditional with Guard Clauses(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)
問(wèn)題:函數(shù)中的條件邏輯使人難以看清正常的執(zhí)行路徑
解決:使用衛(wèi)語(yǔ)句表現(xiàn)所有特殊情況(啟哥備注:可以減少嵌套)
//重構(gòu)前 double getPayAmount(){ double result; if(_isDead) result = deadAmount; else{ if(_isSeparated) result = separatedAmount(); else{ if(_isRetired) result = retiredAmount(); else result = normalPayAmount(); } } return result; }
//重構(gòu)后 double getPayAmount(){ if(_isDead) return deadAmount(); if(_isSeparated) return separatedAmount(); if(_isRetired) return retiredAmount; return normalPayAmount(); }動(dòng)機(jī)
條件表達(dá)式通常有兩種表現(xiàn)形式:
第一種是:所有分支都屬于正常行為
第二種是:條件表達(dá)式提供的答案中只有一種是正常行為,其他都是不常見(jiàn)的情況
如果某個(gè)條件極其罕見(jiàn),就應(yīng)該多帶帶檢查該條件,并在該條件為真時(shí)立刻從函數(shù)中返回,這樣的多帶帶檢查常常被稱為”衛(wèi)語(yǔ)句”
做法對(duì)于每個(gè)檢查,放進(jìn)一個(gè)衛(wèi)語(yǔ)句,衛(wèi)語(yǔ)句要么從函數(shù)中返回,要么就拋出一個(gè)異常
每次將條件檢查替換成衛(wèi)語(yǔ)句后,編譯并測(cè)試
范例:將條件反轉(zhuǎn)//重構(gòu)前 public double getAdjustedCapital(){ double result = 0.0; if(_capital > 0.0){ if(_intRate > 0.0 && _duration > 0.0){ result = (_income / _duration) * ADJ_FACTOR; } } return result; }
//重構(gòu)后 public double getAdjustedCapital(){ double result = 0.0; if(_capital <= 0.0) return 0.0; if(_intRate <= 0.0 || _duration <= 0.0) return 0.0; return (_income / _duration) * ADJ_FACTOR; }Replace Conditional with Polymorphism(以多態(tài)取代條件表達(dá)式)
問(wèn)題:你手上有個(gè)條件表達(dá)式,他根據(jù)對(duì)象類型的不同而選擇不同的行為
解決:將條件表達(dá)式的每個(gè)分支放進(jìn)一個(gè)子類內(nèi)的覆寫(xiě)函數(shù)中,然后將原始函數(shù)聲明為抽象函數(shù)
//重構(gòu)前 double getSpeed(){ switch(_type){ case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactory() * _numberOfCoconuts; case NORWEGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException("Should be unreachable"); }
==>
//重構(gòu)后
多態(tài)最根本的好處就是:如果需要根據(jù)對(duì)象的不同類型而采取不同的行為,多態(tài)使你不必編寫(xiě)明顯的條件表達(dá)式
做法如果要處理的條件表達(dá)式是一個(gè)更大函數(shù)中的一部分,首先對(duì)條件表達(dá)式進(jìn)行分析,然后使用Extract Method將它提煉到一個(gè)獨(dú)立函數(shù)中
如果有必要,使用Move Method(搬移函數(shù))將條件表達(dá)式放置到繼承結(jié)構(gòu)的頂端
任選一個(gè)子類,在其中建立一個(gè)函數(shù),使之覆寫(xiě)超類中容納條件表達(dá)式的那個(gè)函數(shù),將與該子類相關(guān)的條件表達(dá)式分支復(fù)制到新建函數(shù)中,并對(duì)它進(jìn)行適當(dāng)調(diào)整
編譯,測(cè)試
在超類中刪除條件表達(dá)式內(nèi)被復(fù)制了的分支
編譯,測(cè)試
針對(duì)條件表達(dá)式的每個(gè)分支,重復(fù)上述過(guò)程,直到所有分支都被移動(dòng)子類內(nèi)函數(shù)為止
將超類之中容乃條件表達(dá)式的函數(shù)聲明為抽象函數(shù)
范例請(qǐng)?jiān)试S我繼續(xù)使用「員工與薪資」這個(gè)簡(jiǎn)單而又乏味的例子。
繼承構(gòu):
//重構(gòu)前 class Employee... int payAmount(int type){ switch(type){ case Employee.ENGINEER: return _monthlySalary; case Employee.SALESMAN: return _monthlySalary + _commission; case Employee.MANAGER: return _monthlySalary + _bonus; default: throw new IllegalArgumentException("Incorrect type code value"); } } private Employee _type; int getType(){ return _type.getTypeCode() } abstract class EmployeeType... abstract int getTypeCode(); class Engineer extends EmployeeType... int getTypeCode(){ return Employee.ENGINEER: } ...and other subclasses
switch 語(yǔ)句已經(jīng)被很好地提煉出來(lái),因此我不必費(fèi)勁再做一遍。不過(guò)我需要將它移至EmployeeType class,因?yàn)镋mployeeType 才是被subclassing 的class 。
class EmployeeType... int payAmount(Employee emp) { switch (getTypeCode()) { case ENGINEER: return emp.getMonthlySalary(); case SALESMAN: return emp.getMonthlySalary() + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException("Incorrect Employee"); } }
由于我需要EmployeeType class 的數(shù)據(jù),所以我需要將Employee 對(duì)象作為參數(shù)傳遞給payAmount()。這些數(shù)據(jù)中的一部分也許可以移到EmployeeType class 來(lái),但那是另一項(xiàng)重構(gòu)需要關(guān)心的問(wèn)題了。
調(diào)整代碼,使之通過(guò)編譯,然后我修改Employee 中的payAmount() 函數(shù),令它委托(delegate,轉(zhuǎn)調(diào)用)EmployeeType :
class Employee... int payAmount() { return _type.payAmount(this); }
現(xiàn)在,我可以處理switch 語(yǔ)句了。這個(gè)過(guò)程有點(diǎn)像淘氣小男孩折磨一只昆蟲(chóng)——每次掰掉它一條腿(意思就是「去掉一個(gè)分支」)。首先我把switch 語(yǔ)句中的"Engineer"這一分支拷貝到Engineer class:
class Engineer... int payAmount(Employee emp) { return emp.getMonthlySalary(); }
這個(gè)新函數(shù)覆寫(xiě)了superclass 中的switch 語(yǔ)句之內(nèi)那個(gè)專門(mén)處理"Engineer"的分支。我是個(gè)徧執(zhí)狂,有時(shí)我會(huì)故意在case 子句中放一個(gè)陷阱,檢查Engineer class 是否正常工作(是否被調(diào)用):
class EmployeeType... int payAmount(Employee emp) { switch (getTypeCode()) { case ENGINEER: throw new RuntimeException ("Should be being overridden"); case SALESMAN: return emp.getMonthlySalary() + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException("Incorrect Employee"); } }
接下來(lái),我重復(fù)上述過(guò)程,直到所有分支都被去除為止:
class Salesman... int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getCommission(); } class Manager... int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getBonus(); }
然后,將superclass 的payAmount() 函數(shù)聲明為抽象函數(shù):
class EmployeeType... abstract int payAmount(Employee emp);
a
Introduce Null Object(引入Null 對(duì)象)問(wèn)題:你需要再三檢查某物是否為null value
解決:將null值替換為null對(duì)象
if (customer == null) plan = BillingPlan.basic(); else plan = customer.getPlan();
//重構(gòu)后
啟哥說(shuō): 和提供一個(gè)默認(rèn)的不做任何處理的空實(shí)現(xiàn)是一個(gè)意思
動(dòng)機(jī)(Motivation)當(dāng)實(shí)例變量的某個(gè)字段內(nèi)容允許為null時(shí),在進(jìn)行操作時(shí)往往要進(jìn)行非空判斷,這個(gè)工作是非常繁雜的,
所以不讓實(shí)例變量被設(shè)為null,而是插入各式各樣的空對(duì)象——它們都知道如何正確地顯示自己,這樣就可以擺脫大量過(guò)程化的代碼
空對(duì)象一定是常量,它們的任何成分都不會(huì)發(fā)生變化,因此可以使用Singleton模式來(lái)實(shí)現(xiàn)它們
做法為源類建立一個(gè)子類,使其行為就像是源類的null版本,在源類和null子類中都加上isNull()函數(shù),前者的應(yīng)該返回false,后者的應(yīng)該返回true,或者建立一個(gè)nullable接口,將isNull()函數(shù)放入其中,讓源類實(shí)現(xiàn)這個(gè)接口
編譯
找出所有”索求源對(duì)象卻獲得一個(gè)null”的地方,修改這些地方,使它們改而獲得一個(gè)空對(duì)象
找出所有”將源對(duì)象與null做比較”的地方,修改這些地方,使它們調(diào)用isNull()函數(shù)
編譯,測(cè)試
找出這樣的程序點(diǎn):如果對(duì)象不是null,做A動(dòng)作,否則做B動(dòng)作
對(duì)于每一個(gè)上述地點(diǎn),在null類中覆寫(xiě)A動(dòng)作,使其行為和B動(dòng)作相同
使用上述被覆寫(xiě)的動(dòng)作,然后刪除”對(duì)象是否等于null”的條件測(cè)試,編譯并測(cè)試
范例—家公用事業(yè)公司的系統(tǒng)以Site 表示地點(diǎn)(場(chǎng)所)。庭院宅等和集合公寓(apartment)都使用該公司的服務(wù)。任何時(shí)候每個(gè)地點(diǎn)都擁有(或說(shuō)都對(duì)應(yīng)于)一個(gè)顧客,顧客信息以Customer 表示:
//重構(gòu)前 class Site... Customer getCustomer(){ return _customer; } Customer _customer; class Customer... public String getName(){...} public BillingPlan getPlan(){...} public PaymentHistory getHistory(){...} public class PaymentHistory... int getWeesDelingquentInLastYear() Customer customer = site.getCustomer(); BillingPlan plan; if(customer == null) plan = BillingPlan.basic(); else plan = customer.getPlan(); ...
//重構(gòu)后 class NullCustomer extens Customer{ public boolean isNull(){ return true; } } class Customer... public boolean isNull(){ return false; } static Customer new Null(){ return new NullCustomer(); } class Site... Customer getCustomer(){ return (_customer == null) ? Customer.newNull() : _customer; } Customer customer = site.getCustomer(); BillingPlan plan; if(customer.isNull()) plan = BillingPlan.basic(); else plan = customer.getPlan();Introduce Assertion(引入斷言)
問(wèn)題:如果某一段代碼需要對(duì)程序狀態(tài)做出某種假設(shè)
解決:以斷言明確表現(xiàn)這種假設(shè)
//重構(gòu)前 double getExpenseLimit(){ return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit:_primaryProject.getMemberExpenseLimit(); }
//重構(gòu)后 double getExpenseLimit(){ Assert.isTrue(_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit:_primaryProject.getMemberExpenseLimit(); }動(dòng)機(jī)
常常會(huì)有這樣一段代碼:只有當(dāng)某個(gè)條件為真時(shí),該段代碼才能正常運(yùn)行,這時(shí)應(yīng)該使用斷言,把不符合條件的假設(shè)標(biāo)明出來(lái)
斷言可以作為交流與調(diào)試的輔助,在交流的角度上,斷言可以幫助程序閱讀者理解代碼所做的假設(shè);在調(diào)試的角度上,斷言可以在距離bug最近的地方抓住它們
在一段邏輯中加入斷言是有好處的,因?yàn)?strong>它迫使你重新考慮這段代碼的約束條件,如果不滿足這些約束條件,程序也可以正常運(yùn)行,斷言就不會(huì)帶給你任何幫助,只會(huì)把代碼變得混亂,并且有可能妨礙以后的修改
做法如果你發(fā)現(xiàn)代碼假設(shè)某個(gè)條件始終為真,就加入一個(gè)斷言明確說(shuō)明這種情況
范例下面是一個(gè)簡(jiǎn)單例子:開(kāi)支(經(jīng)費(fèi))限制。后勤部門(mén)的員工每個(gè)月有固定的開(kāi)支限額;業(yè)務(wù)部門(mén)的員工則按照項(xiàng)目的開(kāi)支限額來(lái)控制自己的開(kāi)支。一個(gè)員工可能沒(méi)有開(kāi)支額度可用,也可能沒(méi)有參與項(xiàng)目,但兩者總得要有一個(gè)(否則就沒(méi)有經(jīng)費(fèi)可用 了)。在開(kāi)支限額相關(guān)程序中,上述假設(shè)總是成立的,因此:
//重構(gòu)前 class Employee... private static final double NULL_EXPENSE = -1.0; private double _expenseLimit = NULL_EXPENSE; private Project _primaryProject; double getExpenseLimit() { return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } boolean withinLimit (double expenseAmount) { return (expenseAmount <= getExpenseLimit()); }
這段代碼包含了一個(gè)明顯假設(shè):任何員工要不就參與某個(gè)項(xiàng)目,要不就有個(gè)人開(kāi)支限額。我們可以使用assertion 在代碼中更明確地指出這一點(diǎn):
double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }
這條assertion 不會(huì)改變程序的任何行為。另一方面,如果assertion中的條件不為真,我就會(huì)收到一個(gè)運(yùn)行期異常:也許是在withinLimit() 函數(shù)中拋出一個(gè)空指針(null pointer)異常,也許是在Assert.isTrue() 函數(shù)中拋出一個(gè)運(yùn)行期異常。有時(shí)assertion 可以幫助程序員找到臭蟲(chóng),因?yàn)樗x出錯(cuò)地點(diǎn)很近。但是,更多時(shí)候,assertion 的價(jià)值在于:幫助程序員理解代碼正確運(yùn)行的必要條件。
我常對(duì)assertion 中的條件式使用Extract Method ,也許是為了將若干地方的重復(fù)碼提煉到同一個(gè)函數(shù)中,也許只是為了更清楚說(shuō)明條件式的用途。
//重構(gòu)后 double getExpenseLimit() { Assert.isTrue (Assert.ON && (_expenseLimit != NULL_EXPENSE || _primaryProject != null)); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }
或者是這種手法
//重構(gòu)后 double getExpenseLimit() { Assert.isTrue (Assert.ON && (_expenseLimit != NULL_EXPENSE || _primaryProject != null)); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }
如果Assert.ON 是個(gè)常量,編譯器(譯注:而非運(yùn)行期間)就會(huì)對(duì)它進(jìn)行檢查; 如果它等于false ,就不再執(zhí)行條件式后半段代碼。但是,加上這條語(yǔ)句實(shí)在有點(diǎn)丑陋,所以很多程序員寧可僅僅使用Assert.isTrue() 函數(shù),然后在項(xiàng)目結(jié)束前以過(guò)濾程序?yàn)V掉使用assertions 的每一行代碼(可以使用Perl 之類的語(yǔ)言來(lái)編寫(xiě)這樣 的過(guò)濾程序)。
Assert class應(yīng)該有多個(gè)函數(shù),函數(shù)名稱應(yīng)該幫助程序員理解其功用。除了isTrue() 之外,你還可以為它加上equals() 和shouldNeverReachHere() 等函數(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67989.html
摘要:但條件邏輯也是不能忽視的分解條件表達(dá)式問(wèn)題有一個(gè)復(fù)雜的條件語(yǔ)句。沒(méi)什么說(shuō)的動(dòng)機(jī)重構(gòu)代碼就是錯(cuò)移除控制標(biāo)志問(wèn)題在一系列布爾表達(dá)式中,某個(gè)變量帶有控制標(biāo)記的作用方法以語(yǔ)句或語(yǔ)句取代控制標(biāo)記動(dòng)機(jī)控制標(biāo)記大大降低了代碼可讀性。 前言 前面已經(jīng)對(duì)類,方法,字段都進(jìn)行了重構(gòu)。貌似看起來(lái)很完整了。但條件邏輯也是不能忽視的 分解條件表達(dá)式 問(wèn)題 有一個(gè)復(fù)雜的條件(if-then-else)語(yǔ)句。(判斷...
摘要:函數(shù)改名問(wèn)題函數(shù)的名稱未能揭示函數(shù)的用途。這些人甚至?xí)跇?gòu)造函數(shù)中使用設(shè)值函數(shù)。方法將構(gòu)造函數(shù)替換為工廠函數(shù)。以上所說(shuō)的情況,常會(huì)在返回迭代器或集合的函數(shù)身上發(fā)生。以異常取代錯(cuò)誤碼問(wèn)題某個(gè)函數(shù)返回一個(gè)特定的代碼,用以表示某種錯(cuò)誤情況。 Rename Method 函數(shù)改名 問(wèn)題 函數(shù)的名稱未能揭示函數(shù)的用途。 方法 修改函數(shù)名稱。 動(dòng)機(jī) 好的函數(shù)需要有一個(gè)清晰的函數(shù)名。保證一看就懂 A...
摘要:重構(gòu)在不改變代碼的外在的行為的前提下對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率本質(zhì)上,就是代碼寫(xiě)好之后修改它的設(shè)計(jì)。重構(gòu)可以深入理解代碼并且?guī)椭业?。同時(shí)重構(gòu)可以減少引入的機(jī)率,方便日后擴(kuò)展。平行繼承目的在于消除類之間的重復(fù)代碼。 重構(gòu) (refactoring) 在不改變代碼的外在的行為的前提下 對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率 本質(zhì)上, 就是代碼寫(xiě)好之后 修改它的設(shè)計(jì)。 1,書(shū)中...
摘要:為何重構(gòu)重構(gòu)有四大好處重構(gòu)改進(jìn)軟件設(shè)計(jì)如果沒(méi)有重構(gòu),程序的設(shè)計(jì)會(huì)逐漸腐敗變質(zhì)。經(jīng)常性的重構(gòu)可以幫助維持自己該有的形態(tài)。你有一個(gè)大型函數(shù),其中對(duì)局部變量的使用使你無(wú)法采用。將這個(gè)函數(shù)放進(jìn)一個(gè)單獨(dú)對(duì)象中,如此一來(lái)局部變量就成了對(duì)象內(nèi)的字段。 哪有什么天生如此,只是我們天天堅(jiān)持。 -Zhiyuan 國(guó)慶抽出時(shí)間來(lái)閱讀這本從師傅那里借來(lái)的書(shū),聽(tīng)說(shuō)還是程序員的必讀書(shū)籍。 關(guān)于書(shū)的高清下載連...
閱讀 948·2021-11-22 12:09
閱讀 3715·2021-09-27 13:36
閱讀 1403·2021-08-20 09:37
閱讀 4027·2019-12-27 12:22
閱讀 2365·2019-08-30 15:55
閱讀 2370·2019-08-30 13:16
閱讀 2832·2019-08-26 17:06
閱讀 3442·2019-08-23 18:32