標籤:
模板方法模式
在一個演算法中定義了一個演算法骨架,而將一些演算法延遲到子類中。模板方法使得子類可以再不改變演算法結構的情況下,重新定義演算法中的某些步驟。
演算法中的鉤子(hook):鉤子是一種被聲明在抽象類別中的方法,但只有空的或者預設的實現。鉤子的存在,是子類能夠針對演算法的不同點進行掛鈎。要不要掛鈎,由子類自行決定。預設鉤子方法
一個鉤子方法常常由抽象類別給出一個空實現作為此方法的預設實現。這種空的鉤子方法叫做“Do Nothing Hook”。顯然,這種預設鉤子方法在預設適配模式裡面已經見過了,一個預設適配模式講的是一個類為一個介面提供一個預設的空實現,從而使得預設適配類的子類不必像實現介面那樣必須給出所有方法的實現,因為通常一個具體類並不需要所有的方法。
命名規則
命名規則是設計師之間賴以溝通的管道之一,使用恰當的命名規則可以協助不同設計師之間的溝通。
鉤子方法的名字應當以do開始,這是熟悉設計模式的Java開發人員的標準做法。在上面的例子中,鉤子方法hookMethod()應當以do開頭;在HttpServlet類中,也遵從這一命名規則,如doGet()、doPost()等方法。
來源: <http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html>
模板方法模式符合好萊塢設計原則: 別調用(打電話給)我們,我們會調用(打電話給)你 在好萊塢原則下:我們允許底層組件掛鈎到系統上,但是高層組件會決定什麼時候和使用這些底層組件。換句話說,高層組件對待底層組件的方式是:“別調用我,我會調用你們” 下面是一個沖泡咖啡和茶的例子
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public abstract class DrinkTemplet {public void prepareDrink(){//模板方法boilWater();//燒水brew();//沖泡pourIncup();//把飲料倒進杯子中if(CustomerNeedCondiments()){//鉤子函數用來控制 模板中的方法String answer =getUserInput();addCodiemnts(answer);}}final void addCodiemnts(String condiments) {System.out.println("4、把"+condiments+"加入到飲料中!");} String getUserInput(){String answer = "null";return answer; }final void pourIncup() {System.out.println("3、把開水倒進杯子中!");}boolean CustomerNeedCondiments() {//鉤子函數return false;}abstract void brew();final void boilWater() {System.out.println("1、燒熱水!");}}
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Tea extends DrinkTemplet{//具體的子類@Overridevoid brew() {System.out.println("2、drop tea into the cup");}@Overrideboolean CustomerNeedCondiments() {boolean flag =false;System.out.println("would you like add some codiments in your tea?(y/n)");BufferedReader br = new BufferedReader(new InputStreamReader(System.in));try {if(br.readLine().startsWith("y")){flag=true;}} catch (IOException e) {// todo auto-generated catch blocke.printStackTrace();}return flag;} String getUserInput() {String answer ="null";try {System.out.println("what you want add in your tea?");BufferedReader br = new BufferedReader(new InputStreamReader(System.in));answer =br.readLine();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return answer;}}
下面是摘自別人的部落格中的 模板模式的應用:來源: <http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html>
模板方法模式在Servlet中的應用
使用過Servlet的人都清楚,除了要在web.xml做相應的配置外,還需繼承一個叫HttpServlet的抽象類別。HttpService類提供了一個service()方法,這個方法調用七個do方法中的一個或幾個,完成對用戶端調用的響應。這些do方法需要由HttpServlet的具體子類提供,因此這是典型的模板方法模式。下面是service()方法的原始碼:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn‘t support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
當然,這個service()方法也可以被子類置換掉。
下面給出一個簡單的Servlet例子:
從上面的類圖可以看出,TestServlet類是HttpServlet類的子類,並且置換掉了父類的兩個方法:doGet()和doPost()。
public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("using the GET method"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("using the POST method"); }}
從上面的例子可以看出這是一個典型的模板方法模式。
HttpServlet擔任抽象模板角色
模板方法:由service()方法擔任。
基本方法:由doPost()、doGet()等方法擔任。
TestServlet擔任具體模板角色
TestServlet置換掉了父類HttpServlet中七個基本方法中的其中兩個,分別是doGet()和doPost()。
Java模板方法模式