您的瀏覽器不支援JavaScript功能,若網頁功能無法正常使用時,請開啟瀏覽器JavaScript狀態
Antfire 的生活雜記
Skip
    • 首頁
    • Blog
    • 重構心法之迴圈切割術(Split ...

    重構心法之迴圈切割術(Split Loop)

    迴圈切割術(Split Loop)

    Split Loop 單從字面上的意思來看,就是把迴圈分開。
    意思就是,當一個迴圈中,同時做了兩件以上不同的工作的時候,就應該把這些工作拆開來。
    因為如果都濃縮在同一個迴圈的話,雖然可以一個迴圈就做完所有的工作,但會造成閱讀上的困難,如果要修改其中一個工作,要先分析完迴圈中所有工作在做的內容才能進行修改。
    拆開迴圈的話,等於將不同的工作分別拆開來,對於之後的維護幫助很大。

    在使用迴圈切割術的時候,常常會接著使用函式擷取術(Extract Function),可以更清楚了解每個迴圈的工作內容。

    手術流程

    1. 複製迴圈
    2. 消除重複的工作內容
    3. 記得要測試功能是否正常運作
    4. 函式擷取術 (opt.)

    範例

    let youngest = people[0] ? people[0].age : Infinity;
    let totalSalary = 0;
    for (const p of people) {
      if (p.age < youngest) youngest = p.age;
      totalSalary += p.salary;
    }
    
    return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
    

    範例中有一個迴圈,在做兩個不同的工作。一個是在計算最年輕多少歲數;一個是計算薪水加總。
    根據上面的手術流程,我們首先複製迴圈

    複製迴圈

    let youngest = people[0] ? people[0].age : Infinity;
    let totalSalary = 0;
    for (const p of people) {
      if (p.age < youngest) youngest = p.age;
      totalSalary += p.salary;
    }
    
    for (const p of people) {
      if (p.age < youngest) youngest = p.age;
      totalSalary += p.salary;
    }
    
    return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
    

    消除重複的工作內容

    let youngest = people[0] ? people[0].age : Infinity;
    let totalSalary = 0;
    for (const p of people) {
      //if (p.age < youngest) youngest = p.age;
      totalSalary += p.salary;
    }
    
    for (const p of people) {
      if (p.age < youngest) youngest = p.age;
     //totalSalary += p.salary;
    }
    
    return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
    

    記得做測試

    到目前為止,迴圈切割術已經完成了,並且經測試功能正常,再來,可以考慮函式擷取術了。
    但在這之前,我們先使用陳述句滑動術(Slide Statements)讓程式碼更好閱讀,也能讓函式擷取術更順利執行。

    陳述句滑動術

    let totalSalary = 0;
    for (const p of people) {
      //if (p.age < youngest) youngest = p.age;
      totalSalary += p.salary;
    }
    
    let youngest = people[0] ? people[0].age : Infinity;
    for (const p of people) {
      if (p.age < youngest) youngest = p.age;
     //totalSalary += p.salary;
    }
    
    return `youngestAge: ${youngest}, totalSalary: ${totalSalary}`;
    

    函式擷取術

    return `youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`;
    
    function totalSalary() {
      let totalSalary = 0;
      for (const p of people) {
        totalSalary += p.salary;
      }
      return totalSalary;
    }
    
    function youngestAge() {
      let youngest = people[0] ? people[0].age : Infinity;
      for (const p of people) {
        if (p.age < youngest) youngest = p.age;
      }
      return youngest;
    }
    

    補充

    作者說他很難抗拒用迴圈取代管線術 (Replace Loop with Pipeline)計算總薪資,以及用迭代演算法(Substitute Algorithm)計算最年輕年齡。

    return `youngestAge: ${youngestAge()}, totalSalary: ${totalSalary()}`;
    
    function totalSalary() {
      return people.reduce((tota, p) => total + p.salary, 0);
    }
    
    function youngestAge() {
      return Math.min(...people.map(p => p.age));
    }
    

    參考文獻

     Comments