Summary:
有一個大型函數,其中對局部變量的使用使你無法采用Extract Method。将這個函數放進一個單獨對象中,如此一來局部變量就成了對象内的字段。然後可以在同一個對象中将這個大型函數分解為多個小型函數。
Motivation:
局部變量的存在會增加函數分解的難度。如果一個函數之中局部變量泛濫成災,那麼想分解這個函數是非常困難的。Replace Temp with Query可以幫助減輕這一負擔,但是有時候根本無法拆解一個需要拆解的函數。這種情況下,就要用到函數對象(method object)這一法寶。
Replace Method with Method Object 會将所有局部變量都變成函數對象的字段然後可以對這個新對象使用Extract Method 創造出新函數,進而将原本的大型函數拆解變短。
Mechanics:
1. 建立一個新類,根據待處理函數的用途,為這個類命名
2. 在新類中建立一個final字段,用以儲存原先大型函數所在的對象。我們将這個字段稱為“源對象”。同時,針對原函數的每個臨時變量和每個參數,在新類中建立一個對應的字段儲存之。
3.在新類中建立一個構造函數,接受源對象及原函數的所有參數作為參數。
4.在新類中建立一個compute () 函數。
5. 将原函數的代碼複制到compute () 函數中。如果需要調用源對象的任何函數,請通過源對象字段調用。
6. 編譯
7. 将舊函數的函數本體替換為這樣一條語句:“建立上述新類的一個新對象,而後調用其中的compute () 函數”。
範例
public class Account
{
int gamma( int inputVal, int quantity, int yearToDate )
{
int importantValue1 = ( inputVal * quantity ) + delta();
int importantValue2 = ( inputVal * yearToDate ) + 100;
if( ( yearToDate - importantValue1 ) > 100 )
{
importantValue2 -= 20;
}
int importantValue3 = importantValue2 * 7;
//and so on.
return importantValue3 - 2 * importantValue1;
}
}
為了把這個函數變成一個函數對象,我們需要首先聲明一個新類。在此新類中我們應該提供一個final字段用以儲存源對象;對于函數的每一個參數和每一個臨時變量,也以一個字段逐一儲存。 為了保持小步前進,我們暫時先保留這些字段的原名。然後,加入一個構造函數
class Gamma{
private final Account account;
private int inputVal;
private int quantity;
private int yearToDate;
private int importantValue1;
private int importantValue2;
private int importantValue3;
Gamma( Account source, int inputValArg, int quantityArg, int yearToDateArg )
{
account = source;
inputVal = inputValArg;
quantity = quantityArg;
yearToDate = yearToDateArg;
}
}
現在可以把原本的函數搬到compute() 了。函數中任何調用Account類的地方,我們都必須改而使用account字段。
int compute()
{
int importantValue1 = ( inputVal * quantity ) + account.delta();
int importantValue2 = ( inputVal * yearToDate ) + 100;
if( ( yearToDate - importantValue1 ) > 100 )
{
importantValue2 -= 20;
}
int importantValue3 = importantValue2 * 7;
//and so on.
return importantValue3 - 2 * importantValue1;
}
然後,修改舊函數,讓它将工作委托給剛完成的這個函數對象。
int gamma( int inputVal, int quantity, int yearToDate )
{
return new Gamma(this, inputVal, quantity, yearToDate).compute();
}
這就是本項重構的基本原則。它帶來的好處是:現在我們呢可以輕松地對compute()函數采取Extract Method, 不必擔心參數傳遞的問題。