重構|重構方法彙總&代碼Demo

重構方法數組

從新組織函數

提煉函數 Extract Method

function printOwing($amount){
    printBanner();
    
    // print details
    echo NAME;
    echo $amount;
}

/** Refactor **/

function printOwing($amount){
    printBanner();
    printDetails($amount);
}

function printDetails($amount){
    echo NAME;
    echo $amount;
}

動機: 當遇到過長的函數或者一段須要註釋才能讓人理解的代碼時使用。數據結構

當遇到局部變量時,要當心!併發

當發現源函數的參數被賦值時,應該使用Remove Assignments to Parameters方法。分佈式

內聯函數-Inline Method

function getRating(){
    return moreThanFiveLateDeliveries() ? 2 : 1;
}

function moreThanFiveLateDeliveries(){
    return NUMBER_OF_LATE_DELIVERIES > 5;
}
/** R **/

int getRating(){
    return NUMBER_OF_LATE_DELIVERIES > 5 ? 2 : 1;
}

注意:重構函數不該具備多態性ide

內聯臨時變量-Inline Temp

$basePrice = AnOrder->basePrice();
return $basePrice > 1000;

/** R **/

return AnOrder->basePrice() > 1000;

動機:Inline Temp多半是做爲Replace Temp with Query的一部分使用的。函數

查詢渠道臨時變量-Replace Temp with Query

$basePrice = $quantity * $itemPrice;
if($basePrice > 1000){
    return $basePrice * 0.95;
}else{
    return $basePrice * 0.98;
}

/** R **/

function basePrice(){
    return $quantity * $itemPrice;
}

if(basePrice() > 1000){
    return basePrice() * 0.95;
}else{
    return basePrice() * 0.98;
}

動機:將臨時變量做爲查詢,同一個類中的全部函數都可以訪問設計

注意:要肯定下來final型的變量,爲了更好的編寫後續程序。code

引入解釋性變量-Introduce Explaining Variable

if((Platform->toUpperCase()->indexOf("MAC") > -1)
 && (Browser->toUpperCase()->indexOf("IE") > -1)
 && wasIntialized() && $resize > 0)
 {
     // Do sth
 }

/** R **/

final boolean isMacOs = Platform->toUpperCase()->indexOf("MAC") > -1;
final boolean isIEBrowser = Browser->toUpperCase()->indexOf("IE") > -1;
final boolean wasResized = resize > 0;

if(isMacOs && isIEBrowser && wasIntialized() && wasResized){
    // Do sth
}

動機:消除複雜表達式,用臨時變量解釋、歸總每一步的意義orm

分解臨時變量-Split Temporary Variable

拒絕臨時變量的屢次賦值,致使不一樣位置而具備不一樣意義。server

移除對參數的賦值-Remove Assignments to Parameters

function discount($inputVal, $quantity, $yearToDate){
    if($inputVal > 50){
        $inputVal -= 2;
    }
}

/** R **/

function discount($inputVal, $quantity, $yearToDate){
    $result = $inputVal;
    if($inputVal > 50){
        $result -= 2;
    }
}

拒絕對參數賦值,保持對參數入出不變。

以函數對象取代類中函數-Replace Method with Method Object

若是一個函數過大(問題函數),考慮新建一個類來代替這個問題函數。

在對象之間搬移特性-決定責任歸屬

搬移函數-Move Method

若是一個類與另外一個類有太多合做而造成高度耦合,則須要搬移函數,構建新類。

搬移字段-Move Field

同理上面的方法。

提煉類-Extract Class

若是某個類作了兩個類作的事情,考慮新建一個類來處理。

將類內聯化-Inline Class

若是某個類沒有作太多事情,能夠將這個類的特性搬移到另外一個類中,移除原類。

隱藏委託關係-Hide Delegate

客戶經過一個委託類來調用另外一個對象。在服務類上創建客戶所需的全部函數,用以隱藏委託關係。

移除中間人-Remove Middle Man

某個類作了過多的簡單委託動做。這個時候能夠考慮讓客戶直接調用受託類。

引入外加函數-Introduce Foreign Method

你須要位提供服務的類增長一個函數,但你沒法修改這個類時。

能夠在客戶類中創建一個函數,並以第一參數形式傳入一個服務類實例。

$newStart = new Date(PreviousEnd->getYear(), PreviousEnd->getMonth(), PreviousEnd->getDate() + 1);

/** R **/

$newStart = nextDay(PreviousEnd);

function nextDay($date){
    return new Date($date->getYear(), $date->getMonth(), $date->getDate() + 1);
}

引入本地擴展-Introduce Local Extension

你須要爲服務類提供一些額外函數,但你沒法修改這個類。

那麼就新建一個類,使它包含這些額外函數。讓這個擴展類稱爲源類的子類或者包裝類。

本地擴展的兩種方式:

  1. 就是經過繼承-構建子類來做出對源類的擴展。

  2. 經過構建包裝類:將源類經過構造函數傳入包裝類,包裝類對源類的每個函數都進行再處理,經過包裝類調用源類。

從新組織數據

經過對象來表示數據類型,即Replace Value with Object,即經過函數訪問每個數據。

把數組變成對象,能夠更好的展露數組的數據結構。

自封裝字段-Self Encapsulate Field

private $_low, $_high;

function includes($arg){
    return $arg >= self::$_low && $arg <= self::$_high;
}

/** R **/

private $_low, $_high;

function includes($arg){
    return $arg >= getLow() && $arg <= getHigh();
}

function getLow(){
    return self::$_low;
}

function getHigh(){
    return self::$_high;
}

以對象取代數據值-Replace Data Value with Object

動機:開發初期,每每決定以簡單的數據表示簡單的狀況。可是隨着開發深刻,發現簡單數據項也須要一些其它的概念或特殊行爲。此時就能夠把數據值抽象出來,變成一個可操做的對象。

將值對象改成引用對象-Change Value to Reference

當你從一個類衍生出許多彼此相等的實例時,但願將他們替換爲同一個對象進行操做

那麼就將這個值對象變成引用對象。這樣來保證全部操做的實物是同一個實物(每每是真實世界中同一個物體)。

將引用對象改成值對象-Change Reference to Value

在分佈式系統和併發系統中,不可變的值對象特別有用。由於你無需考慮他們的同步問題。

值對象自己應有一個特性:他們是不可變的。若是保證了這一點,就能夠以多個對象表示同一個事物。若是是可變的,則考慮使用引用對象。

以對象取代數組-Replace Array with Object

複製‘被監視數據’-Duplicate Observed Data

view層數據和controller邏輯數據是須要拆分出來的。若是兩層系統使用了一樣的數據,那麼view層能夠經過觀察者模式(Observer/Observable模式)來得到領域類的數據。

也可使用事件監聽器來取代觀察者模型,每當領域對象發生變化,就向監聽器發送一個事件。view層系統在適當時候調用update。

雙向關聯 & 單向關聯

使用字面常量

封裝字段

若是類中存在public字段,則將它聲明爲private,並提供相應的訪問函數。

以類和子類取代類型碼(Type Code)

參考

  1. 重構-改善既有代碼的設計

相關文章
相關標籤/搜索