重構-Simplifying Conditional Expressions

Refactor
(圖片來自: http://sourcemaking.com/)
以下為學習 Simplifying Conditional Expressions 的筆記.

Consolidate Conditional Expression

看原文例子比較容易懂! 一系列條件測試且都回傳相同的值,可將其集中成同一個條件式,然後抽取成一個方法.

優點: 簡化程式碼.

Consolidate Duplicate Conditional Fragments

看原文例子比較容易懂! 每個條件測試之後,若有相同的程式碼片段(代表每個條件都會執行該段程式碼),將其搬出讓所有條件共用程式碼片段.

優點: 簡化程式碼.

Decompose Conditional

看原文例子比較容易懂! 當程式碼中有複雜的條件陳述區段時,將 條件判斷 和 條件判斷內的程式碼 各自抽取成新的方法.

優點: 簡化原本複雜的條件陳述區段.

Introduce Assertion

利用 Assert 來驗證程式內的假設是否正確.

優點: 驗證意想不到的錯誤.

Introduce Null Object

系統中常常出現 "判斷某個物件是否為 null 的判斷式",產生一個空物件來取代 null.

Class NullCompany extends Company
{
  /* 取得員工數目. */
  public int getStaffNumber()
  {
    return 0;
  }

  /* 取得公司住址. */
  public String getAddress()
  {
    return "";
  }
}

/* 若沒有空物件的寫法. */
int staffNumber;
if (rebarCompany = null)
{
  staffNumber = 0;
}
else
{
  staffNumber = rebarCompany.getStaffNumber();
}
...
String address;
if (rebarCompany = null)
{
  address = "";
}
else
{
  address = rebarCompany.getAddress();
}

/* 使用空物件的寫法.
* 若該公司被掏空,就會傳進一個 NullCompany .
* 這樣空物件跟一般物件都共用同一段程式碼. */
int staffNumber =
  rebarCompany.getStaffNumber(); // NullCompany 回傳0.
...
String address =
  rebarCompany.getAddress(); // NullCompany 回傳空字串.

優點: 處理為 null 時的預設行為,全部集中至空物件中. 簡化原本需要判斷並處理 Null 的區段.

Remove Control Flag

看例子比較容易懂! 當程式中有一個用來當做條件控制旗標的變數,用 break 或 return 來取代.

以下為原文範例: 囧rz

/* 是否跟崩潰有關,一找到就停止比對. */
bollean isFound = false; // Control Flag.
for (int i = 0; i < list.length; i++)
{
  if (isFound == false)
  {
    if (list[i].equals("魚翔拳"))
    {
      isFound = true;
    }
    else if (list[i].equal("蔡老頭"))
    {
      isFound = true;
    }
    else if (list[i].equal("五分埔"))
    {
      isFound = true;
    }
  }
}

/* 是否跟崩潰有關,一找到就停止比對. */
for (int i = 0; i < list.length; i++)
{
  if (list[i].equals("魚翔拳"))
  {
    break;
  }
  else if (list[i].equal("蔡老頭"))
  {
    break;
  }
  else if (list[i].equal("五分埔"))
  {
    break;
  }
}

優點: 簡化邏輯.

Replace Conditional with Polymorphism

條件判斷後的行為是根據物件的類型決定時,將其不同的行為抽出到各自的子類別(使用多型)當中.

多型

/* 原本程式. */
String name = people.getName();
if (name.equal("AskaYang"))
{
  System.out.prinln("我只是喜歡唱歌!!(哭哭)");
}
else if (name.equal("YuXiangChuan"))
{
  System.out.println("嗚~(崩潰中)");
}
else if (name.equal("YangShinHsuan"))
{
  System.out.println("我有憂鬱症!(藥袋上看診時間:案發後一天)");
}

Class AskaYang extends People
{
  public String doSomethingWrong()
  {
    return "我只是喜歡唱歌!!(哭哭)";
  }
}

Class YuXianChuan extends People
{
  public String doSomethingWrong()
  {
    return "嗚~(崩潰中)";
  }
}

Class YangShinHsuan extends People
{
  public String doSomethingWrong()
  {
    return "我有憂鬱症!(藥袋上看診時間:案發後一天)";
  }
}

...

/* 修改後的程式.
* 根據傳入的 People 子類別的不同,印出不同的訊息. */
System.out.println(people.doSomethingWrong());

優點: 當程式中反覆使用相同的條件判斷時,利用多型將不同行為封裝至子類別,原本程式碼中的條件判斷 可改成 傳入不同子類別 來取代.

Replace Nested Conditional with Guard Clauses

當巢狀判斷迴圈無法清楚表示出執行路徑時,使用 Guard Cluse 取代所有其他情形.

  • 當使用 if - else 架構時,代表 if 跟 else 內的程式片段一樣重要.
  • 當使用 Guard Cluse 時,代表 "這是很少發生的事件,若發生請做處理然後跳出!"
  • 一個方法只有一個入口,但不一定只有一個出口(一個 Return).

/* 又帥又有錢才能做我的男朋友. */
public boolean beMyBoyFriend(People boy)
{
  boolean result = false;
  if (boy.isPoor())
  {
    result = false;
  }
  else
  {
    if (boy.isUgly())
    {
      result = false;
    }
    else
    {
      result = true;
    }
  }
  return result;
}

/* 使用 Guard Cluse. */
public boolean beMyBoyFreind(People boy)
{
  if (boy.isPoor()) // Guard Cluse.
  {
    return false;
  }
 
  if (boy.isUgly) // Guard Cluse
  {
    return false;
  }


  return true;
}

優點: 增加閱讀性.

延伸閱讀: XD
壓力大到變狼人? 楊士萱公開道歉認錯 坦承伸鹹豬手
楊宗緯坦承年齡造假灑淚別星光
余祥銓(維基百科)

0 則回應: