1. 程式人生 > >重構---重構手法-----以查詢取代臨時變數(Replace Temp with Query)

重構---重構手法-----以查詢取代臨時變數(Replace Temp with Query)

本文轉載,原作者:皮斯特勞沃

開門見山

發現:你的程式以一個臨時變數儲存某一表達式的運算結果。

        解決:將這個表示式提煉到一個獨立函式中。將這個臨時變數的所有引用點替換為對新函式的呼叫。

  //重構前
    double basePrice = _quantity * _itemPrice;
    if(basePrice > 5000)
        return basePrice * 0.95;
    else
        return basePrice * 0.98;
    //重構後
    if(basePrice() > 5000)
        return basePrice() * 0.95;
    else
        return basePrice() * 0.98;
    ...

    double basePrice(){
         return  _quantity * _itemPrice;
    }

動機

        我們都知道臨時變數都是暫時的,而且只能在所屬的函式中使用。所以它們會驅使你寫出更長的函式,因為只有這樣你才能訪問到需要的臨時變數。如果把臨時變數替換為一個查詢,那麼同一個類中所有函式都將可以獲得這份資訊。這將帶給你極大幫助,使你能夠為這個類編寫出更清晰的程式碼。

        該重構方法往往是你運用提煉函式之前必不可少的一個步驟。區域性變數會使得程式碼難以提煉,所以應該儘可能把它們替換為查詢式。比較簡單的情況是:臨時變數只被賦值一次,或者賦值給臨時變數的表示式不受其它條件影響。

做法

        對於簡單的情況: (1)找出只被賦值依次的臨時變數(如果被使用多次,考慮將其分割成多個變數,對應在後續重構方法中)。
(2)將該臨時變數宣告為final。 (3)編譯(確保該臨時變數的確只被賦值一次) (4)將“對該臨時變數賦值”之語句的等號右側部分提煉到一個獨立的函式中。(首先將函式宣告為private。日後你可能會發現還有好多地方需要使用它,那時放鬆對它的保護也很容易;確保提煉出的函式無任何副作用,即該函式不修改任何物件內容) (5)編譯,測試。 (6)對該臨時變數實施“內聯臨時變數”重構方法。

        我們常常使用臨時變數儲存迴圈中的累加資訊。在這種情況下,整個迴圈都可以被提煉為一個獨立的函式,這可以減少原函式中幾行迴圈邏輯程式碼。該手法的使用可能會讓你擔心效能上的問題。就像和其它效能問題一樣,我們現在不用管它,因為十有八九根本沒有造成任何影響。就算真的出問題了,你也可以在優化時期解決它。程式碼組織良好,你也會發現更有效的優化方案;如果沒有進行重構,好的優化方案就可能與你失之交臂。


示例

        我們從一個簡單函式開始:
//重構前
double getPrice() {
    int basePrice = _quantity * _itemPrice;
    double discountFactor;
    if (basePrice > 5000)
        discountFactor = 0.95;
    else
        discountFactor = 0.98;
    return basePrice * discountFactor;
}
        我們希望將其中的兩個臨時變數都去掉。當然,每次一個進行處理。
        程式碼雖然簡單,但是還是有必要先把臨時變數宣告為final,檢查它們是否的確只被賦值一次。
double getPrice() {
    final int basePrice = _quantity * _itemPrice;
    final double discountFactor;
    if (basePrice > 5000)
        discountFactor = 0.95;
    else
        discountFactor = 0.98;
    return basePrice * discountFactor;
}
        這樣,一旦有問題編譯器就會警告。之所以需要這個做是因為如果臨時不安路口不只被賦值一次,就不該進行這項重構。         下面開始替換臨時變數,每次一個,不要著急,按部就班。         首先,把賦值動作右側表示式提煉出來:
double getPrice() {
    final int basePrice = basePrice();
    final double discountFactor;
    if (basePrice > 5000)
        discountFactor = 0.95;
    else
        discountFactor = 0.98;
    return basePrice * discountFactor;
}

private double basePrice() {
    return _quantity * _itemPrice;
}
        然後,編譯並測試,再開始使用內聯臨時變數。         首先把臨時變數basePrice的第一個引用點替換掉:
double getPrice() {
    final int basePrice = basePrice();
    final double discountFactor;
    if (basePrice() > 5000)
        discountFactor = 0.95;
    else
        discountFactor = 0.98;
    return basePrice * discountFactor;
}
        編譯、測試,然後進行下一個。由於下一個是最後一個引用點,所以把basePrice臨時變數的宣告式一併去掉:
double getPrice() {
    final double discountFactor;
    if (basePrice() > 5000)
        discountFactor = 0.95;
    else
        discountFactor = 0.98;
    return basePrice()  * discountFactor;
}
        完成basePrice之後,以類似的方法提煉出discountFactor():
double getPrice() {
    final double discountFactor = discountFactor() ;
    return basePrice()  * discountFactor;
}

private double discountFactor(){
    if (basePrice() > 5000)
        return 0.95;
    else
        return 0.98;
}
        你會發現,如果沒有把臨時變數basePrice替換為一個查詢式,將多麼難以提煉discountFactor()!         最終,getPrice()變成這樣:
//重構後
double getPrice() {
    return basePrice()  * discountFactor();
}

本文轉載,原作者:皮斯特勞沃

相關推薦

重構---重構手法-----查詢取代臨時變數Replace Temp with Query

本文轉載,原作者:皮斯特勞沃 開門見山 發現:你的程式以一個臨時變數儲存某一表達式的運算結果。         解決:將這個表示式提煉到一個獨立函式中。將這個臨時變數的所有引用點替換為對新函式的呼叫。 //重構前 double basePrice = _quantity * _itemPr

重構二:查詢取代臨時變數

如果你的程式中有一個臨時變數,他的賦值操作是通過一個表示式來進行的,那我們可以把這個表示式單獨提煉出一個函式,在源程式中對變數的引用改為對這個函式的引用。 動機 如果在一個函式內部通過表示式對一個臨時變數賦值,這驅使你會寫出越來越長的程式碼,因為只用這樣你才能訪問到臨時變數,而且這

重構筆記——查詢取代臨時變數

 在上一篇文章中介紹了“ 內聯臨時變數“。本文將介紹“以查詢取代臨時變數”這種重構手法。   下面讓我們來學習這種重構手法吧。 開門見山 發現:你的程式以一個臨時變數儲存某一表達式的運算結果。

6.4 Replace Temp with Query 查詢取代臨時變數

將表示式提煉到一個獨立方法中,將這個臨時變數的所有引用點替換為對新方法的呼叫 更多精彩 更多技術部落格,請移步 asing1elife’s blog 前置條件 該方法通常是 6.1 Extract Method 提煉方法 的前置條件

重構改善既有代碼設計--重構手法05:Introduce Explaining Variable 引入解釋性變量

其中 size 語句 臨時變量 變量名 內聯 some ria tro 發現:你有一個復雜的表達式。 解決:將該復雜的表達式(或其中的部分)的結果放進一個臨時變量,並以此變量名稱來解釋表達式用途。 //重構前 if((platform.toUpperC

重構改善既有代碼設計--重構手法18:Self Encapsulate Field 自封裝字段

擁有 bsp range 設值 測試 void end sub tcap 你直接訪問一個值域(field),但與值域之間的耦合關系逐漸變得笨拙。 為這個值域建立取值/設值函數(getting/setting methods),並且只以這些函數來訪問值域。 priv

HQL的多表查詢 left jon 等 需要配置一對多

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

設定Windows防火牆允許被ICMP Ping兩種配置方式

本文由荒原之夢原創,原文連結:http://zhaokaifeng.com/?p=1119 背景與目的 Ping測試常被用於測試網路中兩臺主機之間是否互相連通,但是,大多數Windows作業系統(包括桌面版和伺服器版)預設都是隻允許ping其他主機而不允許其他主機ping自己。下

MAC OSX 新增環境變數最簡單的方式

echo 'export PATH="/Users/aa/PostgreSQL/pg95/bin"' >> ~/.bash_profil 直接在命令列裡面執行以上命令即可,就是這麼簡單。 這裡是把 export PATH=" " 這行新增進了 ~/.bas

多表查詢,內連線隱式、顯示,外連線左外、右外、基礎表

from子句進行多表查詢 例如:查詢分數資訊,顯示玩家暱稱、遊戲名稱和分數 select user_name as '暱稱', gname as '遊戲名稱', score as '分數'

08、共享變數Broadcast Variable和Accumulator

 Spark提供的Broadcast Variable,是只讀的。並且在每個節點上只會有一份副本,而不會為每個task都拷貝一份副本。因此其最大作用,就是減少變數到各個節點的網路傳輸消耗,以及在各個節點上的記憶體消耗。此外,spark自己內部也使用了高效的廣播演算法來減少網路消耗。可以通過呼叫SparkCon

Spark SQL將rdd轉換為資料集-程式設計方式指定模式Programmatically Specifying the Schema

一:解釋 官網:https://spark.apache.org/docs/latest/sql-getting-started.html 這種場景是生活中的常態 When case classes cannot be defined ahead of time (for example

沒有躲過的坑--類中的靜態成員變數static or const static

工作中是這樣的,A類中有一個成員變數x,最開始宣告為私有: class A{ private: int x; }; 現在需要在另一個cpp中使用這個x,所以要把它變為共有並且靜態: class A{ public: static int

c/c++ 繼承與多型 文字查詢的小例子非智慧指標版本

問題:在上一篇繼承與多型 文字查詢的小例子(智慧指標版本)在Query類裡使用的是智慧指標,只把智慧指標換成普通的指標,並不新增拷貝構造方法,會發生什麼呢? 執行時,程式碼崩掉。 分析下面一行程式碼: Query qb = ~Query("Alice"); 1,首先呼叫Query(string)的建構

Mybatis+MySQL動態分頁查詢資料經典案例含程式碼以及測試

             最近在用Mybatis做專案的時候遇到了不少問題,今天我就在這和大家分享一下,稀稀拉拉的研究了兩天,終於搞好了!     開發人員:1111     開發軟體:Myeclipse     用到的框架技術:Mybatis     資料庫:MySql  

解決MacOS UE4中C++建立Object出錯UE4關聯配置Xcode

錯誤資訊1: Xcode installed on this Mac is too old to be used for Metal shader compilation. Falling back to runtime compiled text shaders, which are slowe

小程式或js,判斷變數Undefined String Array Object是否為空

關鍵程式碼 function isBlank(str){ if (Object.prototype.toString.call(str) ==='[object Undefined]'){//

2.4變動和最終變數Volatile and Final Variables

在前面的學習同步鎖顯示了兩個屬性:互斥和可見性。同步關鍵字連線著這兩個屬性。Java提供一個弱引用的僅僅用於同步可見性。它也連線著一個volatile的關鍵字。 假設你設計一個機制去停止一個執行緒(因為你不能用Thread的stop()方法,在這個任務中它是不安全的)。Li

static靜態成員與非靜態變數和普通成員方法的關係

1.static ( 被其修飾的是靜態成員類成員,屬於整個類所有,不是針對某個物件即類中所有物件所有。           可以使用類名訪問,也可以使用物件名訪問 ) 使用之靜態變數   static可修飾變數、方法、程式碼塊   1)靜態成員(方法)能直接呼叫(訪問)靜態成

二叉查詢樹的實現插入+遞迴呼叫

package BinaryTree; public class BinarySearchTree { public TreeNode root; public BinarySearchTree(){ //root=new TreeNode(1,"A");