詳細(xì)介紹優(yōu)化函數(shù)的構(gòu)成
下面介紹了幾種優(yōu)化函數(shù):
1. Extract Method (提煉函數(shù))
解釋:
如果發(fā)現(xiàn)一個(gè)函數(shù)的代碼很長(zhǎng), 很可能的一種情況是這個(gè)函數(shù)做了很多事情, 找找看函數(shù)中有沒(méi)有注釋, 往往注釋都是為了解釋下面一塊代碼做的什么事情, 可以考慮將這塊代碼提煉(Extract)成一個(gè)獨(dú)立的函數(shù).
這樣做的好處不言而喻, 是面向?qū)ο笪宕蠡驹瓌t中的單一職責(zé)原則 (Single Responsibility Principle), 比較長(zhǎng)的函數(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ù)中的代碼.物件中過(guò)多的方法會(huì)讓人感到不舒服, 干掉完全不必要的函數(shù)后代碼會(huì)更簡(jiǎn)潔.
沖動(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í)變量?jī)?nèi)聯(lián))
解釋:
如果有一個(gè)臨時(shí)變量 (Temp)用來(lái)表示某個(gè)函數(shù)的返回值, 一般來(lái)說(shuō), 這樣的做法挺好的. 但如果這個(gè)臨時(shí)變量實(shí)在多余, 將這個(gè)臨時(shí)變量?jī)?nèi)聯(lián)之后毫不影響代碼的閱讀, 甚至這個(gè)臨時(shí)變量妨礙了其它重構(gòu)工作, 就應(yīng)該將這個(gè)臨時(shí)變量?jī)?nèi)聯(lián)化.
把這個(gè)臨時(shí)變量干掉的好處在于減少了函數(shù)的長(zhǎng)度, 有時(shí)可以讓其它重構(gòu)工作更順利的進(jìn)行.
沖動(dòng)前:
- int salary = employee.Salary;
- return (salary > 10000);
沖動(dòng)后:
- return (employee.Salary > 10000);
- Replace Temp With Query (用查詢(xún)式代替臨時(shí)變量)
解釋:
程序中有一個(gè)臨時(shí)變量(Temp)用來(lái)保存某個(gè)表達(dá)式的計(jì)算結(jié)果, 將這個(gè)計(jì)算表達(dá)式提煉(Extract)到一個(gè)獨(dú)立的函數(shù)(即查詢(xún)式Query)中, 將這個(gè)臨時(shí)變量所有被調(diào)用的地方換成對(duì)新函數(shù)(Query)的調(diào)用, 新函數(shù)還可以被其它函數(shù)使用.
好處在于減少函數(shù)長(zhǎng)度, 增加代碼復(fù)用率, 有利于代碼進(jìn)一步的重構(gòu). 并且注意 Replace Temp With Query 往往是 Extract Method 之前必不可少的步驟, 因?yàn)榫植孔兞繒?huì)使代碼不太容易被提煉, 所以在進(jìn)行類(lèi)似的重構(gòu)前可以將它們替換成查詢(xún)式.
下面的這個(gè)例子不是很有必要使用Replace Temp With Query, 主要展示如何 Replace Temp With Query. 試想"沖動(dòng)前"函數(shù)中有很多個(gè)代碼塊都使用到 totalPrice, 突然有一天我發(fā)現(xiàn)這個(gè)函數(shù)太長(zhǎng), 我需要將這一塊塊的代碼提煉成單獨(dú)的函數(shù), 這樣就需要將 totalPrice = price * num; 放到每一個(gè)提煉出來(lái)的函數(shù)中. 而如果原來(lái)函數(shù)中使用的是查詢(xún)式, 就不存在這個(gè)問(wèn)題. 如果查詢(xún)式中的計(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á)式中, 很多條件令人難以理解它的意義, 為什么要滿(mǎn)足這個(gè)條件? 不清楚. 可以使用Introduce Explaining Variable將每個(gè)條件子句提煉出來(lái), 分別用一個(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ù)上面某處表示長(zhǎng)方形周長(zhǎng), 在函數(shù)下面被賦予面積, 也就是這個(gè)臨時(shí)變量被賦值超過(guò)一次, 且表示的不是同一種量. 應(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ù)的值無(wú)可厚非, 因?yàn)槲覀兙褪窍敫淖冊(cè)瓉?lái)的值. 但如果是"傳值", 在代碼中為參數(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)的寫(xiě)下一行行代碼后, 突然發(fā)現(xiàn)這個(gè)函數(shù)變得非常大, 而且由于這個(gè)函數(shù)包含了很多局部變量, 使得無(wú)法使用 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è)笑話:
某跨國(guó)日化公司, 肥皂生產(chǎn)線存在包裝時(shí)可能漏包肥皂的問(wèn)題, 肯定不能把空的肥皂盒賣(mài)給顧客, 于是該公司總裁命令組成了以博士牽頭的專(zhuān)家組對(duì)這個(gè)問(wèn)題進(jìn)行攻關(guān), 該研發(fā)團(tuán)隊(duì)使用了世界上***精尖的技術(shù) (如紅外探測(cè), 激光照射等), 在花費(fèi)了大量美金和半年的時(shí)間后終于完成了肥皂盒檢測(cè)系統(tǒng), 探測(cè)到空的肥皂盒以后, 機(jī)械手會(huì)將空盒推出去. 這一辦法將肥皂盒空填率有效降低至5%以?xún)?nèi), 問(wèn)題基本解決.
而某鄉(xiāng)鎮(zhèn)肥皂企業(yè)也遇到類(lèi)似問(wèn)題, 老板命令初中畢業(yè)的流水線工頭想辦法解決之, 經(jīng)過(guò)半天的思考, 該工頭拿了一臺(tái)電扇到生產(chǎn)線的末端對(duì)著傳送帶猛吹, 那些沒(méi)有裝填肥皂的肥皂盒由于重量輕就都被風(fēng)吹下去了...
這個(gè)笑話可以很好的解釋 Substitute Algorithm, 對(duì)于函數(shù)中復(fù)雜的算法, 盡量想辦法將這個(gè)算法簡(jiǎn)單化, 從而達(dá)到與之前同樣甚至更好的效果.
本文鏈接: http://www.cnblogs.com/technology/archive/2011/05/10/2042255.html
【編輯推薦】