『重構--改善既有代碼的設計』讀書筆記----Replace Method with Method Object

有時候,當你遇到一個大型函數,裏面的臨時變量和參數多的讓你以爲根本沒法進行Extract Method。重構中也大力的推薦短小函數的好處,它所帶來的解釋性,複用性讓你收益無窮。但若是你遇到上種狀況,你可能會天真的覺得我只要適當的進行Replace Temp with Query,就能夠把這種現象給化解。但狀況每每事與願違,不能達到你所理想的高度。這個時候你須要用到重構中的殺手鐗--Replace Method with Method Object,這個手法出自Kent Beck [Beck]。html

簡單的說,這個重構會把源函數內的全部局部變量的參數都變成Method Object的字段。而後由於是字段,因此就不存在臨時變量這個限制,你就能夠輕輕鬆鬆的對新對象的新函數進行Extract Method將原來的大型函數進行輕鬆拆解。函數

作法:this

  • 創建一個新類,根據待處理函數的用途,爲這個類起個好名字。
  • 在新類中創建一個const字段,用來保存源函數所在的對象,咱們將這個函數稱爲源對象。同時針對原函數的每一個臨時變量和參數,咱們都在新類中增長相應的字段進行保存。
  • 在新類中創建一個構造函數,其中構造函數的參數爲原對象和原函數的參數(注意:字段裏須要同時存儲原函數的參數和臨時變量,可是構造函數只須要原函數的參數
  • 在新類增長一個compute()函數
  • 將原函數的代碼複製到新對象的compute()函數中,而後把原函數中對原對象的調用都改爲對新類中包含原對象的字段的調用。
  • 編譯
  • 將舊函數的函數本體替換成建立上述新類的一個對象,而後對用它的compute()函數

完成這些以後,你就能夠對新類中的compute()函數進行大刀闊斧的改造了。spa

例子:code

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; return importantValue3 - 2 * importantValue1; }

這是咱們的原函數,能夠看到,參數和臨時變量很是多,很是難以進行Extract Method。因此是時候用出咱們的殺手鐗,首先按照『作法』,咱們新建一個新類,而後將這個函數的參數和臨時變量都變成他的字段。htm

class Gamma
{
    private:
        const Account *m_account;
        int inputVal;
        int quantity;
        int yearToDate;
        int importantValue1;
        int importantValue2;
        int importantValue3;
};

爲了保證重構的小步進行,這裏咱們不對字段變量進行任何更名,這樣有其何處,當你將原函數的實現搬過來的時候,你暫時不須要進行任何修改。對象

接下來咱們進行構造函數的聲明,注意:這個時候你只須要將原函數的所在對象和所需參數看成構造函數參數便可,不須要全部的臨時變量。blog

    public:
        Gamma(Account *account, int inputValArg, int quantityArg, int yearToDateArg) :
            m_account(account),
            inputVal(inputValArg),
            quantity(quantityArg),
            yearToDate(yearToDateArg)
        {
        }

接下來,咱們聲明compute()函數,而且將原函數的實現搬過來,講裏面的聲明刪除,由於已是新類的字段了,而後將對源對象自己的函數調用替換成對字段的調用,完整實現以下get

class Gamma
{
    public:
        Gamma(Account *account, int inputValArg, int quantityArg, int yearToDateArg) :
            m_account(account),
            inputVal(inputValArg),
            quantity(quantityArg),
            yearToDate(yearToDateArg)
        {
        }

        int compute()
        {
            importantValue1 = (inputVal * quantity) + m_account->delta();
            importantValue2 = (inputVal * yearToDate) + 100;

            if ((yearToDate - importantValue1) > 100)
                importantValue2 -= 20;

            importantValue3 = importantValue2 * 7;

            return importantValue3 - 2 * importantValue1;
        }

    private:
        const Account *m_account;
        int inputVal;
        int quantity;
        int yearToDate;
        int importantValue1;
        int importantValue2;
        int importantValue3;
};

注意,其中的delta()函數,此時已經變成了m_account->delta(),而且全部變量的聲明都已經被刪除。input

完成了這一步以後,其實咱們已經結束了本次重構手法,但還沒完,咱們之因此運用Replace Method with Method Object就是爲了更好的進行Extract Method,因此接下來,咱們就能夠輕輕鬆鬆對新類新函數進行重構,好比

     class Gamma...
        int compute()
        {
            importantValue1 = (inputVal * quantity) + m_account->delta();
            importantValue2 = (inputVal * yearToDate) + 100;

            importThing();

            return importantValue3 - 2 * importantValue1;
        }

    private:
        void importThing()
        {
            if ((yearToDate - importantValue1) > 100)
                importantValue2 -= 20;
        }

這樣,咱們就輕鬆作到了對compute()函數的無參化的Extract Method,整個實現更加簡潔,不須要去擔憂參數傳遞的問題。最後咱們來看下最終被咱們重構以後原函數的內容

class Account...

int gamma(int inputVal, int quantity, int yearToDate)
{
    return new Gamma(this, inputVal, quantity, yearToDate).compute();
}

原函數的實現變的異常簡潔以外,咱們能夠對新類函數進行各類重構,最後就能夠獲得一個很好的重構效果。

相關文章
相關標籤/搜索