超實用的設計模式之一–模板方法模式

模板方法模式是我工作中用到最多的模式,這個模式的類圖比較簡單,而且思路也比較簡單,只要有重複的工作,加以抽象,都可以使用模板方法。

模板方法的前提

道理很好講,但是很多人依舊會問,爲什麼他的編碼環境卻沒有這樣的使用情況。

設計模式是基於面向對象的套路,所以脫離不了抽象這個概念,很多情況之所以沒辦法去模式化主要是因爲無法抽象。

我們做一件事情,都是分步驟的,例如去煮咖啡,先準備咖啡,然後水加熱,放咖啡豆,結束後裝入容器。針對這件事情,並不能有什麼想法,抽象的基礎是找共同點,起碼是兩個事物之間的影響的結果,如果還有一件事情是煮茶葉,那麼過程就是準備茶葉,然後水加熱,放茶葉,結束後裝入容器。那麼明顯可以抽象煮東西的這個過程。準備材料,水加熱,放材料,結束後裝入容器。但是另外一件事情是砍柴,那麼這樣貌似就不好找細節上的共同點了。很多情況下,沒有模式主要是場景的問題,編碼就寫一個場景,共同點不好找,純粹靠想象去抽象,可能模式是用上了,但是沒有普及性。效果基本和沒有模式差不多。

類圖

實用的設計模式--模板方法模式

 

模板方法模式的主要的思想就是定製一個流程,每個實現類都去遵循這個流程。這個流程是需要通過具體場景去抽象的。

常見案例

最開始學習web編程的時候都會接觸HttpServlet,寫自己的servlet的時候,要繼承這個類,去重寫doget和dopost。這裏用的就是模板方法模式。具體的流程就在service方法中。

  protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    String method = req.getMethod();
    //get
    if (method.equals("GET"))
    {
      long lastModified = getLastModified(req);
      if (lastModified == -1L)
      {
        doGet(req, resp);
      }
      else
      {
        long ifModifiedSince;
        try
        {
          ifModifiedSince = req.getDateHeader("If-Modified-Since");
        }
        catch (IllegalArgumentException iae)
        {
          long ifModifiedSince;
          ifModifiedSince = -1L;
        }
        if (ifModifiedSince < lastModified / 1000L * 1000L)
        {
          maybeSetLastModified(resp, lastModified);
          doGet(req, resp);
        }
        else
        {
          resp.setStatus(304);
        }
      }
    }
    //head
    else if (method.equals("HEAD"))
    {
      long lastModified = getLastModified(req);
      maybeSetLastModified(resp, lastModified);
      doHead(req, resp);
    }
    //post
    else if (method.equals("POST"))
    {
      doPost(req, resp);
    }
    //put
    else if (method.equals("PUT"))
    {
      doPut(req, resp);
    }
    //delete
    else if (method.equals("DELETE"))
    {
      doDelete(req, resp);
    }
    //options
    else if (method.equals("OPTIONS"))
    {
      doOptions(req, resp);
    }
    //trace
    else if (method.equals("TRACE"))
    {
      doTrace(req, resp);
    }
    else
    {
      String errMsg = lStrings.getString("http.method_not_implemented");
      Object[] errArgs = new Object[1];
      errArgs[0] = method;
      errMsg = MessageFormat.format(errMsg, errArgs);

      resp.sendError(501, errMsg);
    }
  }

在service中對http支持的7中方式都做了處理,剩下的就是每個servlet根據自己的情況覆寫doGet,doHead,doPost,doPut,doDelete,doOptions,doTrace。具體的業務也寫在具體的方法裏,具體是調用的是哪種請求方法由service方法中確認。

思想類似的產物

java的jdbc的操作都是獲取連接,創建statment或者preparestatement,然後執行sql,然後關閉resultset(如果有的話),關閉statement,然後關閉連接。具體和業務相關的其實就是sql,剩下的都是流程化的過程。spring jdbc template就是模板化了這些過程,不同的是,他使用了組合的方式去調用而不是繼承,嚴格意義上不是標準的模板方法,只能說是思想類似。

實戰場景

工作中遇到一個場景就是用模板方法來做一個try catch的異常模板。

場景

最開始寫的代碼出現一個問題,就是有異常沒有處理的話,邏輯都被中斷了。因此需要加入異常處理。要這樣改的地方還有很多。

代碼模板

public class Template {

    public static void main(String[] args) {

        new ExceptionTemplate(){
            @Override
            protected void toDo() {
                //流程
                System.out.println("over");
            }
        }.doWork();

    }

}
//模板類
abstract class ExceptionTemplate{
    public final void doWork(){
         try{
             toDo();
         }catch(Exception e){
             //異常處理方式
         }

    }
    protected  void toDo(){}
}

好處

每個地方的改動都是有限的,都是new一個匿名內部類,調用一下方法,原來的寫的代碼都移動到抽象類方法中,提交的代碼的變動相對比較少,而且不容易出錯,邏輯都在模板裏,只要想好一個就可以了。高質量編程視頻shangyepingtai.xin

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章