模板方法模式是我工作中用到最多的模式,這個模式的類圖比較簡單,而且思路也比較簡單,只要有重複的工作,加以抽象,都可以使用模板方法。
模板方法的前提
道理很好講,但是很多人依舊會問,爲什麼他的編碼環境卻沒有這樣的使用情況。
設計模式是基於面向對象的套路,所以脫離不了抽象這個概念,很多情況之所以沒辦法去模式化主要是因爲無法抽象。
我們做一件事情,都是分步驟的,例如去煮咖啡,先準備咖啡,然後水加熱,放咖啡豆,結束後裝入容器。針對這件事情,並不能有什麼想法,抽象的基礎是找共同點,起碼是兩個事物之間的影響的結果,如果還有一件事情是煮茶葉,那麼過程就是準備茶葉,然後水加熱,放茶葉,結束後裝入容器。那麼明顯可以抽象煮東西的這個過程。準備材料,水加熱,放材料,結束後裝入容器。但是另外一件事情是砍柴,那麼這樣貌似就不好找細節上的共同點了。很多情況下,沒有模式主要是場景的問題,編碼就寫一個場景,共同點不好找,純粹靠想象去抽象,可能模式是用上了,但是沒有普及性。效果基本和沒有模式差不多。
類圖
模板方法模式的主要的思想就是定製一個流程,每個實現類都去遵循這個流程。這個流程是需要通過具體場景去抽象的。
常見案例
最開始學習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