控制圈復(fù)雜度的9種重構(gòu)技術(shù)

一個軟件總是為解決某種特定的需求而產(chǎn)生,時代在發(fā)展,客戶的業(yè)務(wù)也在發(fā)生變化。有的需求相對穩(wěn)定一些,有的需求變化的比較劇烈,還有的需求已經(jīng)消失了,或者轉(zhuǎn)化成了別的需求。在這種情況下,軟件必須相應(yīng)的改變。

考慮到成本和時間等因素,當(dāng)然不是所有的需求變化都要在軟件系統(tǒng)中實(shí)現(xiàn)。但是總的說來,軟件要適應(yīng)需求的變化,以保持自己的生命力。
這就產(chǎn)生了一種糟糕的現(xiàn)象:軟件產(chǎn)品最初制造出來,是經(jīng)過精心的設(shè)計(jì),具有良好架構(gòu)的。但是隨著時間的發(fā)展、需求的變化,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷需要修改。為了實(shí)現(xiàn)變更,不可避免的要違反最初的設(shè)計(jì)構(gòu)架。經(jīng)過一段時間以后,軟件的架構(gòu)就千瘡百孔了。bug越來越多,越來越難維護(hù),新的需求越來越難實(shí)現(xiàn),軟件的架構(gòu)對新的需求漸漸的失去支持能力,而是成為一種制約。最后新需求的開發(fā)成本會超過開發(fā)一個新的軟件的成本,這就是這個軟件系統(tǒng)的生命走到盡頭的時候。

重構(gòu)就能夠最大限度的避免這樣一種現(xiàn)象。系統(tǒng)發(fā)展到一定階段后,使用重構(gòu)的方式,不改變系統(tǒng)的外部功能,只對內(nèi)部的結(jié)構(gòu)進(jìn)行重新的整理。通過重構(gòu),不斷的調(diào)整系統(tǒng)的結(jié)構(gòu),使系統(tǒng)對于需求的變更始終具有較強(qiáng)的適應(yīng)能力。

重構(gòu)可以降低項(xiàng)目的耦合度,使項(xiàng)目更加模塊化,有利于項(xiàng)目的開發(fā)效率和后期的維護(hù)。讓項(xiàng)目主框架突出鮮明,給人一種思路清晰,一目了然的感覺,其實(shí)重構(gòu)是對框架的一種維護(hù)。

那么說到重構(gòu),可能我們普遍認(rèn)為就是改改框架、使用一些最新流行的框架或者技術(shù)等等,我們到底要從哪些方面來對項(xiàng)目進(jìn)行重構(gòu)呢?下面我們進(jìn)入主題:控制圈復(fù)雜度的9種重構(gòu)技術(shù)

  • 提煉函數(shù)

例子:如果某段代碼可以被組織在一起并獨(dú)立出來

void printOwing(double previousAmount)
 {
    Enumeration e = _orders.elements();
    double outstanding = previousAmount * 1.2;
    
      // 打印大標(biāo)題
    System.out.println ("**************************");
    System.out.println ("***** Customer Owes ******");
    System.out.println ("**************************");

    // 計(jì)算未完成的訂單數(shù)量
    while (e.hasMoreElements()) 
    {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount();
    }

    //打印明細(xì)
    System.out.println ("name:" + _name);
    System.out.println ("amount" + outstanding);
}

將這段代碼放進(jìn)一個獨(dú)立函數(shù)中,并讓函數(shù)名稱解釋該函數(shù)的用途

void printOwing(double previousAmount) 
{
    printBanner();
    double outstanding = getOutstanding(previousAmount * 1.2);
    printDetails(outstanding);
}

void printBanner() //打印大標(biāo)題
{
    System.out.println ("**************************");
    System.out.println ("***** Customer Owes ******");
    System.out.println ("**************************");
}

// 計(jì)算未完成的訂單數(shù)量
double getOutstanding(double initialValue) 
{
    double result = initialValue;
    Enumeration e = _orders.elements();
    while (e.hasMoreElements()) 
    {
        Order each = (Order) e.nextElement();
        result += each.getAmount();
    }
    return result;
}

void printDetails (double outstanding) //打印明細(xì)
 {
    System.out.println ("name:" + _name);
    System.out.println ("amount" + outstanding);
}
  • Substitute Algorithm(替換你的算法)

例子:
把當(dāng)前算法重構(gòu)成更清晰的算法

String foundPerson(String[] people)
{
    for (int i = 0; i < people.length; i++) 
    {
        if (people[i].equals ("Don"))
            return "Don";
        if (people[i].equals ("John"))
            return "John";
        if (people[i].equals ("Kent"))
            return "Kent";
    }
    return "";
}

重構(gòu)成更清晰的算法

String foundPerson(String[] people)
{
    List candidates = Arrays.asList(new     
            String[]{"Don", "John","Kent"});
    for (int i=0; i<people.length; i++)
        if (candidates.contains(people[i]))
            return people[i];
    return "";
}
  • Decompose Conditional(分解條件式)

例子:你有一個復(fù)雜的條件語句

if (date.before (SUMMER_START) || date.after(SUMMER_END))
    charge = quantity * _winterRate + _winterServiceCharge;
else 
    charge = quantity * _summerRate;

從if、then、else三個段落中分別提煉出獨(dú)立函數(shù)

if (notSummer(date))
    charge = winterCharge(quantity);
else 
    charge = summerCharge (quantity);
  • Consolidate Conditional Expression(合并條件式)

例子:你有一系列條件判斷,都得到相同結(jié)果

double disabilityAmount() 
{
    if (_seniority < 2) return 0;
    if (_monthsDisabled > 12) return 0;
    if (_isPartTime) return 0;
    // compute the disability amount

將這些判斷合并為一個條件式,并將這個條件式提煉成為一個獨(dú)立函數(shù),函數(shù)名自注釋

double disabilityAmount() 
{
    if (isNotEligableForDisability()) return 0;
    // compute the disability amount
  • Consolidate Duplicate Conditional Fragments(合并重復(fù)的條件片斷)

例子:在條件式的每個分支上有著相同的一段代碼。

if (isSpecialDeal()) 
    {
        total = price * 0.95;
        send();
    }
else 
    {
        total = price * 0.98;
        send();
    }

將這段重復(fù)代碼搬移到條件式之外,避免用拷貝粘貼的方式寫重復(fù)代碼

if (isSpecialDeal())
    total = price * 0.95;
else
    total = price * 0.98;
send();
  • Remove Control Flag(移除控制標(biāo)記)

例子:當(dāng)前代碼使用標(biāo)記變量,可讀性差,容易出錯

void checkSecurity(String[] people) {
    boolean found = false;
    for (int i = 0; i < people.length; i++) {
        if (! found) {
            if (people[i].equals ("Don")){
                sendAlert();
                found = true;
            }
            if (people[i].equals ("John")){
                   sendAlert();
                   found = true;
            }
        }
    }
}

以break和return取代標(biāo)記變量

void checkSecurity(String[] people) {
    for (int i = 0; i < people.length; i++) {     
        if (people[i].equals ("Don")){
            sendAlert();
            break;
        }
        if (people[i].equals ("John")){
            sendAlert();
            break;
        }
    }
}
  • Separate Query from Modifier(將查詢函數(shù)和修改函數(shù)分離)

例子:某個函數(shù)既返回對象狀態(tài)值,又修改對象狀態(tài),建立兩個不同的函數(shù),其中一個負(fù)責(zé)查詢,另一個負(fù)責(zé)修改




  • Parameterize Method(令函數(shù)攜帶參數(shù))

例子:若干函數(shù)做了類似的工作,但在函數(shù)本體中卻
包含了不同的值

Dollars baseCharge()
 {
    double result = Math.min(lastUsage(),100) * 0.03;
    if (lastUsage() > 100) {
        result += (Math.min (lastUsage(),200) - 100) * 0.05;
    };
    if (lastUsage() > 200) {
        result += (lastUsage() - 200) * 0.07;
    };
    return new Dollars (result);
}

建立單一函數(shù),以參數(shù)表達(dá)那些不同的值

Dollars baseCharge() 
{
    double result = usageInRange(0, 100) * 0.03;
    result += usageInRange (100,200) * 0.05;
    result += usageInRange (200, Integer.MAX_VALUE) * 0.07;
    return new Dollars (result);
}

int usageInRange(int start, int end) 
{
    if (lastUsage() > start) 
        return Math.min(lastUsage(),end) -start;
    else 
        return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容