2012年2月21日 星期二

一堆的 if 與 else 時怎麼處理

公司裡有一段 code 是這麼寫著


...
...
String 名稱1;
String 名稱2;
String 名稱3;
if (paramater.equals("actionA")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionB")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionC")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if (paramater.equals("actionC")) {
  名稱1 = ....;
  名稱2 = ....;
  名稱3 = ....;
} else if ....
...
...
...


看到了很多的 if 與 else

這時會有一個問題,就是當我要寫增加或修改時,必須先找到合適的那一段後,再插入自己的程式碼,可能會有一些不方便的地方,如:
1. 程式太過攏長, 久了會不好維護.
2. 當有順序要對掉時, 顯得很麻煩.

於是再不動架構的情況下,找了些資訊看能不能改寫這段程式:
參考了良葛格的筆記(Design Patter). Chain of Responsibility

先看一下改過的程式長什麼樣子,再來討論這個 Design Patter 的用處。

首先程式碼將每一段if else 切成各個 Class 去實作, 而主程式只是將每個 Class 串接起來即可.

其每一個Class 的內容如下:

MailsMetaChain
public class MailsMetaChain extends MetaChain {

  public void handleRequest(HttpServletRequest request) {
    if (getPart(request).equals(PARAM_VALUE_MAILS)) {
      processMailsMetaInfo(request);
    } else if (next != null) {
      next.handleRequest(request);
    } else {
      defaultRequest(request);
    }
  }

  private void processMailsMetaInfo(HttpServletRequest request) {
    String title = new StringBuilder()
          .append(IhergoProperties.get("label.mail"))
          .append(" - ")
          .append(IhergoProperties.get("web.title")).toString();
    setMeta(request, title, "", "");
  }
}

其 extends 的 Class MetaChain
public abstract class MetaChain {

  private static final String PARAAM_KEY_PART = "part";
  private static final String PARAAM_KEY_VIEW = "view";
  private static final String PARAAM_KEY_TAB = "tab";

  ... 中間省略
  
  protected MetaChain next;

  public void setNextMetaChain(MetaChain next) {
    this.next = next;
  }

  /**
   * extends class 必須實做的功能
   * 
   * @param request
   */
  protected abstract void handleRequest(HttpServletRequest request);

  /**
   * 如果沒有 match 到時, 用 default 的
   * 
   * @param request
   */
  protected void defaultRequest(HttpServletRequest request) {
    StringBuilder title = new StringBuilder();
    title.append(IhergoProperties.get("web.title"));
    title.append(" - ");
    title.append(IhergoProperties.get("web.categorys"));
    
    String keyword = IhergoProperties.get("web.keywords");
    String desc = IhergoProperties.get("web.description");
    setMeta(request, title.toString(), keyword, desc);
  }

  /**
   * 抓取 part
   * 
   * @param request
   * @return
   */
  protected String getPart(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_PART),
          "");
    }
    return "";
  }

  /**
   * 抓取 view
   * 
   * @param request
   * @return
   */
  protected String getView(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_VIEW),
          "");
    }
    return "";
  }

  /**
   * 抓取 tab
   * 
   * @param request
   * @return
   */
  protected String getTab(HttpServletRequest request) {
    if (request != null) {
      return StringUtils.defaultIfEmpty(request.getParameter(PARAAM_KEY_TAB), "");
    }
    return "";
  }

  protected void setMeta(HttpServletRequest request, String title,
      String keyword, String desc) {
    
    if (StringUtils.isBlank(title)) {
      title = new StringBuilder()
               .append(IhergoProperties.get("web.title"))
               .append(" - ")
               .append(IhergoProperties.get("web.categorys")).toString();
    }
    
    if (StringUtils.isBlank(keyword)) {
      keyword = IhergoProperties.get("web.keywords");
    }
    
    if (StringUtils.isBlank(desc)) {
      desc = IhergoProperties.get("web.description");
    }
    
    request.setAttribute("titleStr", title);
    request.setAttribute("keywordsStr", keyword);
    request.setAttribute("descriptionStr", desc);
  }

  ...
  ...

}


這樣看起來就很清楚明了了唷!!
其好處,以後只需找到自己的 Class 去修改就可以囉。
來看看Gof寫的一段話:

在一個介面中希望使用者一定可以得到相關的說明主題,如果子元件有說明的話,就顯示相關說明,否則的話就轉發給包括它的容器元件或父元件,以保證使用者的輔助說明請求一定可以得到回應。

當然這不是一種好的解法,也可以再更精進一點,如把每一個實作的 Class 改成 Singleton 必免 new 出太多的 Class
而如果可以改變架構的話,其實可以在進入action時,去實作 setTitle 這個 method ,在 BaseAction 中 implements ISetTitle 即可。

沒有留言:

張貼留言