重構手法之重新組織函式 5

2022-05-01 12:57:07 字數 3226 閱讀 8567

返回總目錄

本小節目錄

你有乙個大型函式,其中對區域性變數的使用使你無法採用extract method。

將這個函式放進乙個單獨物件中,如此一來區域性變數就成了物件內的字段。然後你可以在同乙個物件中將這個大型函式分解為多個小型函式。

我們一直在強調,小型函式優美動人。只要將相對獨立的**從大型函式中提煉出來,就大大提高了函式的可讀性。

但是,區域性變數的存在會增加函式分解難度。如果乙個函式中區域性變數氾濫成災,那麼這個時候replace temp with query可以幫助你。有時候根本無法拆解乙個需要拆解的函式,這時候replace method with method object就發揮作用了。

replace method with method object會將所有區域性變數都變成函式物件的字段。然後就可以對這個新函式使用extract method創造新函式,從而達到拆解的目的。

如果要找到合適的例子,那麼需要很長的篇幅,所以我們杜撰了這樣乙個函式。

class

account

int importantvalue3 = importantvalue2 * 7

;

//and so on...

return importantvalue3 - 2 *importantvalue1;

}public

intdelta()

}

為了把這個函式變成函式物件,首先宣告乙個新類。在新類中,提供乙個字段用於儲存原物件,同時也對函式的每個引數和每個臨時變數,提供字段用於儲存。

class

gamma

接下來,加入乙個建構函式:

public gamma(account account, int inputval, int quantity, int

yeartodate)

接下來,將原本的函式搬到compute()中。

public

intcompute()

_importantvalue3 = _importantvalue2 * 7

;

//and so on...

return _importantvalue3 - 2 *_importantvalue1;

}

完整的gamma函式如下:

class

gamma

public

intcompute()

_importantvalue3 = _importantvalue2 * 7

;

//and so on...

return _importantvalue3 - 2 *_importantvalue1;

}}

最後,修改舊函式,讓它的工作委託給剛完成的這個函式物件。

int gamma(int inputval, int quantity, int

yeartodate)

這就是本項重構的基本原則。它的好處是:現在我們可以輕鬆地對compute()函式採取extract method,不必擔心引數傳遞的問題。

比如說我們對compute進行如下重構:

public

intcompute()

void

getimportantthing()

}

這種重構手法是針對大型函式,而且裡面的區域性變數又有很多,那麼這個重構方法或許會讓你豁然開朗。

你想要把某個演算法替換為另外乙個更清晰的演算法。

將函式本體替換為另乙個演算法。

我敢打賭,你從小到大,肯定做過這樣的題目:請使用兩種以上的解法來回答這道問題。這就是說明,某一道題肯定不只有一種解法,而且某些方法肯定會比另一些更簡單。演算法也是如此。

如果你發現做一件事可以有更清晰的方式,就應該以較清晰的方式取代較複雜的方式。隨著對問題有了更深入的了解,你往往會發現,在原先的做法之外,有更簡單的解決方案,此時,你要做的就是改變原先的演算法。

我們以乙個簡單的函式為例:

string foundperson(string

people)

if (person == "

john")

if (person == "

kent")

}return

string

.empty;

}

通過對這個演算法進行分析,我們發現此時如果用乙個list集合,則函式會更簡單,更清晰。所以,重構之後,**如下:

string foundperson(string

people)

;

foreach (var person in

people)

}return

string

.empty;

}

使用這項重構手法之前,請先確定自己已經盡可能分解了原先函式。替換乙個巨大而複雜的演算法是非常困難的,只有先將它分解為較簡單的小型函式,然後你才能很有把握地進行演算法替換工作。

這幾小節的大標題叫做重新組織函式,顧名思義這些重構手法都是針對函式進行整理,使之更恰當地包裝**。幾乎所有時刻,問題都源於**的壞味道之long method(過長函式)。

對於過長函式,一項重要的重構手法就是extract method,它把一段**從原先函式中提取出來,放進獨立的函式中。而inline method則正好相反,它將乙個函式呼叫替換為該函式本體。

提煉函式時最大的困難就是處理區域性變數,其中乙個便是臨時變數。處理乙個函式時,可以先運用replace temp with query去掉所有可能的臨時變數。如果多個地方使用了某個臨時變數,請先運用split temporary variable將它變得比較容易替換。

如果臨時變數太混亂,難以替換。這時候replace method with method object就該登場了。

引數帶來的問題稍微少一些,前提是你不在函式內賦值給它們。如果你這樣做了,請使用remove assignments to parameters。

函式分解完畢後,我就可以知道如何讓它工作得更好。也許某些演算法還可以改進,讓**更清晰。這就需要substitute algorithm來引入更清晰的演算法。

to be continued...

重構手法之重新組織函式 2

返回總目錄 你的程式以乙個臨時變數儲存某一表示式的運算結果。將這個表示式提煉到乙個獨立函式中。將這個臨時變數的所有引用點替換為對函式的呼叫。此後,新函式就可以被其他函式使用。臨時變數的問題在於 只在當前函式可見。如果你在同類的別的地方訪問這個變數,你就必須重新寫表示式來獲取這個變數,這樣的話你就會在...

重構之重新組織函式 Inline Temp

inline temp 概述 乙個臨時變數,只被乙個簡單表示式賦值一次,而它妨礙了其它重構手法。動機 motivation inline temp多半是作為replace temp with query的一部分來使用。惟一單獨使用inline temp的情況是 你發現某個臨時變數被賦予某個函式呼叫的...

重構之重新組織資料

一.自封裝字段 你直接訪問乙個字段,但與字段之間的耦合關係逐漸變得笨拙。為這個字段建立取值 設值函式,並且只以這些函式來訪問字段。在字段訪問方式這個問題上,存在兩種截然不同的觀點。其中一派認為,在該變數定義所在的類中,你可以自由訪問它 另一派認為,即使在這個類中你也應該只使用訪問函式間接訪問。兩派之...