詳細(xì)介紹優(yōu)化函數(shù)的構(gòu)成
下面介紹了幾種優(yōu)化函數(shù):
1. Extract Method (提煉函數(shù))
解釋:
如果發(fā)現(xiàn)一個(gè)函數(shù)的代碼很長, 很可能的一種情況是這個(gè)函數(shù)做了很多事情, 找找看函數(shù)中有沒有注釋, 往往注釋都是為了解釋下面一塊代碼做的什么事情, 可以考慮將這塊代碼提煉(Extract)成一個(gè)獨(dú)立的函數(shù).
這樣做的好處不言而喻, 是面向?qū)ο笪宕蠡驹瓌t中的單一職責(zé)原則 (Single Responsibility Principle), 比較長的函數(shù)被拆分成一個(gè)個(gè)小函數(shù), 將有利于代碼被復(fù)用.
沖動(dòng)前:
- public void Print(Employee employee)
 - {
 - //print employee's information
 - Console.WriteLine("Name:" + employee.Name);
 - Console.WriteLine("Sex:" + employee.Sex);
 - Console.WriteLine("Age:" + employee.Age);
 - //print employee's salary
 - Console.WriteLine("Salary:" + employee.Salary);
 - Console.WriteLine("Bonus:" + employee.Bonus);
 - }
 
沖動(dòng)后:
- public void Print(Employee employee)
 - {
 - //print employee's information
 - PrintInfo(employee);
 - //print employee's salary
 - PrintSalary(employee);
 - }
 - public void PrintInfo(Employee employee)
 - {
 - Console.WriteLine("Name:" + employee.Name);
 - Console.WriteLine("Sex:" + employee.Sex);
 - Console.WriteLine("Age:" + employee.Age);
 - }
 - public void PrintSalary(Employee employee)
 - {
 - Console.WriteLine("Salary:" + employee.Salary);
 - Console.WriteLine("Bonus:" + employee.Bonus);
 - }
 
2. Inline Method (將函數(shù)內(nèi)聯(lián))
解釋:
有些函數(shù)很短, 只有一兩行, 而且代碼的意圖也非常明顯, 這時(shí)可以考慮將這個(gè)函數(shù)干掉, 直接使用函數(shù)中的代碼.物件中過多的方法會(huì)讓人感到不舒服, 干掉完全不必要的函數(shù)后代碼會(huì)更簡潔.
沖動(dòng)前:
- public bool IsDeserving(int score)
 - {
 - return IsScoreMoreThanSixty(score);
 - }
 - public bool IsScoreMoreThanSixty(int score)
 - {
 - return (score > 60);
 - }
 
沖動(dòng)后:
- public bool IsDeserving(int score)
 - {
 - return (score > 60) ;
 - }
 
3. Inline Temp (將臨時(shí)變量內(nèi)聯(lián))
解釋:
如果有一個(gè)臨時(shí)變量 (Temp)用來表示某個(gè)函數(shù)的返回值, 一般來說, 這樣的做法挺好的. 但如果這個(gè)臨時(shí)變量實(shí)在多余, 將這個(gè)臨時(shí)變量內(nèi)聯(lián)之后毫不影響代碼的閱讀, 甚至這個(gè)臨時(shí)變量妨礙了其它重構(gòu)工作, 就應(yīng)該將這個(gè)臨時(shí)變量內(nèi)聯(lián)化.
把這個(gè)臨時(shí)變量干掉的好處在于減少了函數(shù)的長度, 有時(shí)可以讓其它重構(gòu)工作更順利的進(jìn)行.
沖動(dòng)前:
- int salary = employee.Salary;
 - return (salary > 10000);
 
沖動(dòng)后:
- return (employee.Salary > 10000);
 - Replace Temp With Query (用查詢式代替臨時(shí)變量)
 
解釋:
程序中有一個(gè)臨時(shí)變量(Temp)用來保存某個(gè)表達(dá)式的計(jì)算結(jié)果, 將這個(gè)計(jì)算表達(dá)式提煉(Extract)到一個(gè)獨(dú)立的函數(shù)(即查詢式Query)中, 將這個(gè)臨時(shí)變量所有被調(diào)用的地方換成對(duì)新函數(shù)(Query)的調(diào)用, 新函數(shù)還可以被其它函數(shù)使用.
好處在于減少函數(shù)長度, 增加代碼復(fù)用率, 有利于代碼進(jìn)一步的重構(gòu). 并且注意 Replace Temp With Query 往往是 Extract Method 之前必不可少的步驟, 因?yàn)榫植孔兞繒?huì)使代碼不太容易被提煉, 所以在進(jìn)行類似的重構(gòu)前可以將它們替換成查詢式.
下面的這個(gè)例子不是很有必要使用Replace Temp With Query, 主要展示如何 Replace Temp With Query. 試想"沖動(dòng)前"函數(shù)中有很多個(gè)代碼塊都使用到 totalPrice, 突然有一天我發(fā)現(xiàn)這個(gè)函數(shù)太長, 我需要將這一塊塊的代碼提煉成單獨(dú)的函數(shù), 這樣就需要將 totalPrice = price * num; 放到每一個(gè)提煉出來的函數(shù)中. 而如果原來函數(shù)中使用的是查詢式, 就不存在這個(gè)問題. 如果查詢式中的計(jì)算量很大, 也不建議使用 Replace Temp With Query.
沖動(dòng)前:
- public double FinalPrice(double price, int num)
 - {
 - double totalPrice = price * num;
 - if (totalPrice > 100)
 - return totalPrice * 0.8;
 - else
 - return totalPrice * 0.9;
 - }
 
沖動(dòng)后:
- public double FinalPrice(double price, int num)
 - {
 - if (TotalPrice(price, num) > 100)
 - return TotalPrice(price, num) * 0.8;
 - else
 - return TotalPrice(price, num) * 0.9;
 - }
 - public double TotalPrice(double price, int num)
 - {
 - return price * num;
 - }
 
5. Introduce Explaining Variable (引入可以理解的變量)
解釋:
很多時(shí)候在條件邏輯表達(dá)式中, 很多條件令人難以理解它的意義, 為什么要滿足這個(gè)條件? 不清楚. 可以使用Introduce Explaining Variable將每個(gè)條件子句提煉出來, 分別用一個(gè)恰當(dāng)?shù)呐R時(shí)變量名表示條件子句的意義.
好處在于增加了程序的可讀性.
沖動(dòng)前:
- if((operateSystem.Contains("Windows"))&& (browser.Contatins("IE")))
 - {
 - //do something
 - }
 
沖動(dòng)后:
- bool isWindowsOS = operateSystem.Contains("Windows");
 - bool isIEBrowser = browser.Contatins("IE");
 - if (isWindowsOS && isIEBrowser)
 - {
 - //do something
 - }
 
6. Split Temporary Variable (撇清臨時(shí)變量)
解釋:
例如代碼中有個(gè)臨時(shí)變量在函數(shù)上面某處表示長方形周長, 在函數(shù)下面被賦予面積, 也就是這個(gè)臨時(shí)變量被賦值超過一次, 且表示的不是同一種量. 應(yīng)該針對(duì)每次賦值, 分配一個(gè)獨(dú)立的臨時(shí)變量.
一個(gè)變量只應(yīng)表示一種量, 否則會(huì)令代碼閱讀者感到迷惑.
沖動(dòng)前:
- double temp = (width + height) * 2;
 - //do something
 - temp = width * height;
 - //do something
 
沖動(dòng)后:
- double perimeter = (width + height) * 2;
 - //do something
 - double area = width * height;
 - //do something
 
7. Remove Assignments to Parameters (消除對(duì)參數(shù)的賦值操作)
解釋:
傳入?yún)?shù)分"傳值"和"傳址"兩種, 如果是"傳址", 在函數(shù)中改變參數(shù)的值無可厚非, 因?yàn)槲覀兙褪窍敫淖冊(cè)瓉淼闹? 但如果是"傳值", 在代碼中為參數(shù)賦值, 就會(huì)令人產(chǎn)生疑惑. 所以在函數(shù)中應(yīng)該用一個(gè)臨時(shí)變量代替這個(gè)參數(shù), 然后對(duì)這個(gè)臨時(shí)變量進(jìn)行其它賦值操作.
沖動(dòng)前:
- public double FinalPrice(double price, int num)
 - {
 - price = price * num;
 - //other calculation with price
 - return price;
 - }
 
沖動(dòng)后:
- public double FinalPrice(double price, int num)
 - {
 - double finalPrice = price * num;
 - //other calculation with finalPrice
 - return finalPrice;
 - }
 
8. Replace Method with Method Object (用函數(shù)物件代替函數(shù))
解釋:
沖動(dòng)的寫下一行行代碼后, 突然發(fā)現(xiàn)這個(gè)函數(shù)變得非常大, 而且由于這個(gè)函數(shù)包含了很多局部變量, 使得無法使用 Extract Method, 這時(shí) Replace Method with Method Object 就起到了殺手锏的效果. 做法是將這個(gè)函數(shù)放入一個(gè)單獨(dú)的物件中, 函數(shù)中的臨時(shí)變量就變成了這個(gè)物件里的值域 (field).
沖動(dòng)前:
- class Bill
 - {
 - public double FinalPrice()
 - {
 - double primaryPrice;
 - double secondaryPrice;
 - double teriaryPrice;
 - //long computation
 - ...
 - }
 - }
 
沖動(dòng)后:
- class Bill
 - {
 - public double FinalPrice()
 - {
 - return new PriceCalculator(this).compute();
 - }
 - }
 - class PriceCalculator
 - {
 - double primaryPrice;
 - double secondaryPrice;
 - double teriaryPrice;
 - public PriceCalculator(Bill bill)
 - {
 - //initial
 - }
 - public double compute()
 - {
 - //computation
 - }
 - }
 
9. Substitute Algorithm (替換算法)
解釋:
有這么一個(gè)笑話:
某跨國日化公司, 肥皂生產(chǎn)線存在包裝時(shí)可能漏包肥皂的問題, 肯定不能把空的肥皂盒賣給顧客, 于是該公司總裁命令組成了以博士牽頭的專家組對(duì)這個(gè)問題進(jìn)行攻關(guān), 該研發(fā)團(tuán)隊(duì)使用了世界上***精尖的技術(shù) (如紅外探測, 激光照射等), 在花費(fèi)了大量美金和半年的時(shí)間后終于完成了肥皂盒檢測系統(tǒng), 探測到空的肥皂盒以后, 機(jī)械手會(huì)將空盒推出去. 這一辦法將肥皂盒空填率有效降低至5%以內(nèi), 問題基本解決.
而某鄉(xiāng)鎮(zhèn)肥皂企業(yè)也遇到類似問題, 老板命令初中畢業(yè)的流水線工頭想辦法解決之, 經(jīng)過半天的思考, 該工頭拿了一臺(tái)電扇到生產(chǎn)線的末端對(duì)著傳送帶猛吹, 那些沒有裝填肥皂的肥皂盒由于重量輕就都被風(fēng)吹下去了...
這個(gè)笑話可以很好的解釋 Substitute Algorithm, 對(duì)于函數(shù)中復(fù)雜的算法, 盡量想辦法將這個(gè)算法簡單化, 從而達(dá)到與之前同樣甚至更好的效果.
本文鏈接: http://www.cnblogs.com/technology/archive/2011/05/10/2042255.html
【編輯推薦】















 
 
 

 
 
 
 