1. 程式人生 > >重構 改善既有程式碼的設計 Replace Method with Method Object(以函式物件取代函式)

重構 改善既有程式碼的設計 Replace Method with Method Object(以函式物件取代函式)

你有一個大型函式,其中對區域性變數的使用使你無法採用Extract Method

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

動機

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

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

Replace Method with Method Object會將所有區域性變數都變成函式物件的欄位。然後就可以對這個新函式使用Extract Method創造新函式,從而達到拆解的目的。

範例

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

複製程式碼
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;
       }
       public int Delta()
       {
           return 100;
       }
}
複製程式碼

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

複製程式碼
class Gamma
{

        private readonly Account _account;

        private readonly int _inputVal;

        private readonly int _quantity;

        private readonly int _yearToDate;

        private int _importantValue1;

        private int _importantValue2;

        private int _importantValue3;
}
複製程式碼

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

複製程式碼
public Gamma(Account account, int inputVal, int quantity, int yearToDate)
{
       _account = account;
       _inputVal = inputVal;
       _quantity = quantity;
       _yearToDate = yearToDate;
}
複製程式碼

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

複製程式碼
public int Compute()
{
    _importantValue1 = _inputVal * _quantity + _account.Delta();
    _importantValue2 = _inputVal * _yearToDate + 100;
    if (_yearToDate - _importantValue1 > 100)
    {
       _importantValue2 -= 20;
    }
    _importantValue3 = _importantValue2 * 7;
    //and so on...
    return _importantValue3 - 2 * _importantValue1;
}
複製程式碼

完整的Gamma函式如下:

複製程式碼
class Gamma
{

   private readonly Account _account;

   private readonly int _inputVal;

   private readonly int _quantity;

   private readonly int _yearToDate;

   private int _importantValue1;

   private int _importantValue2;

   private int _importantValue3;
public Gamma(Account account, int inputVal, int quantity, int yearToDate) { _account = account; _inputVal = inputVal; _quantity = quantity; _yearToDate = yearToDate; } public int Compute() { _importantValue1 = _inputVal * _quantity + _account.Delta(); _importantValue2 = _inputVal * _yearToDate + 100; if (_yearToDate - _importantValue1 > 100) { _importantValue2 -= 20; } _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,不必擔心引數傳遞的問題。

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

複製程式碼
public int Compute()
{
    _importantValue1 = _inputVal * _quantity + _account.Delta();
    _importantValue2 = _inputVal * _yearToDate + 100;
    GetImportantThing();
    _importantValue3 = _importantValue2 * 7;
    //and so on...
    return _importantValue3 - 2 * _importantValue1;
}

void GetImportantThing()
{
    if (_yearToDate - _importantValue1 > 100)
    {
        _importantValue2 -= 20;
    }
}
複製程式碼