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


    Replace Temp with Query,顧名思義,表示你用查詢來替換臨時變量本身,臨時變量對於函數來說是只有當前函數可見的,如果你在同類的別的地方要用到這個變量你就必須重新寫表達式來獲取這個變量,這樣的話你就會在不經意間讓你的函數變得復雜起來,所以如果你想要使用Extract Method,那么Replace Temp with Query是必不可少的一個步驟。而我們前面介紹的Inline Temp其實是這個手法的一部分,兩者的區別在於Inline Temp已經有了表達式自身,只需要做簡單的替換就可以,表示用表達式本身把臨時變量給去掉。而Replace Temp with Query更加全面,里面包含了提煉表達式到函數本身,然后替換引用點(Inline Temp)。如果你把所有的臨時變量都替換為一個查詢,你的類的結構和邏輯將非常清晰,這樣將更加有利於你的重構和進行優化。

    這個重構手法有個很重要的前提就是臨時變量只能被賦值一次,或者賦值給臨時變量的表達式不受別的條件約束進行改變。對於其他情況,可能你應該需要Split Temporary Variable或Separate Query from Modifer把情況弄的簡單點之后再運用本手法。對於有那種收集結果的臨時變量或者循環中要進行累積的變量,你需要將程序的邏輯復制到查詢函數中去。

    做法一般都是找到只被賦值一次的臨時變量,然后用const加以修飾進行編譯(表示之后沒有對這個變量進行修改),然后將所有對這個變量等號右邊的表達式提煉到一個函數中去(這個步驟其實已經是Inline Temp的前提條件),然后將這個函數先聲明為private(如果以后有別的類需要再改為public,這樣可以保證接口的整潔性),判斷這個查詢函數本身會不會修改對象內容,如果會的話就需要運用Separate Query from Modifer進行重構。這些步驟都做好之后,就可以用Inline Temp將之前做好的函數進行變量替換。

    有些同學可能會擔心性能問題,我明明一個變量放在那好好的,你不要用,導致你每次去使用多要做一次查詢。對於這種情況大可放心,重構的目的是讓程序更加清晰,有了更加清晰的程序之后再具體做優化也不遲,況且根據二八原則,僅僅這條查詢語句倘若你系統真的出現了性能問題也不大可能,如果實在是因為這條語句,你也可以把變量再放回去。

    下面來看下具體例子:

double getPrice()
{
    int basePrice = m_quanity * m_itemPrice;
    double discountFactor;
    if (basePrice > 1000)
    {
        discountFactor = 0.95
    }
    else
    {
        discountFactor = 0.98
    }
    return basePrice * discountFactor;
}

例子很簡單,但是有兩個臨時變量,可以看到basePrice和discountFactor都被賦值了一次,如果我想重構這個函數,我們上面講到了,Extract Method之前要做Replace Temp with Query,那么用Query來取代這兩個臨時變量那會讓我們更加清晰重構的路線。

    首先第一步,我們來進行basePrice的提煉,在之前加上const,進行編譯,發現沒有問題。

double getPrice()
{
    const int basePrice = m_quanity * m_itemPrice;
    double discountFactor;
    if (basePrice > 1000)
    {
        discountFactor = 0.95
    }
    else
    {
        discountFactor = 0.98
    }
    return basePrice * discountFactor;
}

    然后我們將等號之后的提煉到獨立小函數中去(為了確保查詢函數本身的特質--不修改對象本身,我們這里可以利用C++特性給函數加上const限定)

int basePrice() const
{
    return m_quanity * m_itemPrice;
}

    這樣原來的函數就變成了

double getPrice()
{
    const int basePrice = basePrice();
    double discountFactor;
    if (basePrice > 1000)
    {
        discountFactor = 0.95
    }
    else
    {
        discountFactor = 0.98
    }
    return basePrice * discountFactor;
}

    然后逐步使用Inline Temp把對basePrice的地方進行替換並進行編譯測試,最后直接把basePrice的聲明去掉。重復這個動作來進行提煉discountFactor得到

double getPrice() const
{
    return basePrice() * discountFactor();
}


int basePrice() const
{
    return m_quanity * m_itemPrice;
}

double discountFactor()
{
    if (basePrice() > 1000)
    {
        return 0.95
    }
    else
    {
        return 0.98
    }
}

 
        

    可以看到,在提煉discountFactor的時候,對於臨時變量basePrice如果沒有進行提煉,那么就需要將這個臨時變量傳進去。像這樣

double discountFactor(int basePrice)
{
    if (basePrice > 1000)
    {
        return 0.95
    }
    else
    {
        return 0.98
    }
}

    可以明顯的看到,這個重構手法對於函數本身來說,提高了清晰度,也讓我們進行后期重構能夠更加便捷。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM