日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

《JAVA与模式》之模板方法模式

發(fā)布時(shí)間:2024/9/30 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《JAVA与模式》之模板方法模式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html

英文定義更容易理解:

defines the skeleton of an algorithm in a method. deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

在閻宏博士的《JAVA與模式》一書(shū)中開(kāi)頭是這樣描述模板方法(Template Method)模式的:

  模板方法模式是類的行為模式。準(zhǔn)備一個(gè)抽象類,將部分邏輯以具體方法以及具體構(gòu)造函數(shù)的形式實(shí)現(xiàn),然后聲明一些抽象方法來(lái)迫使子類實(shí)現(xiàn)剩余的邏輯。不同的子類可以以不同的方式實(shí)現(xiàn)這些抽象方法,從而對(duì)剩余的邏輯有不同的實(shí)現(xiàn)。這就是模板方法模式的用意。


模板方法模式的結(jié)構(gòu)

  模板方法模式是所有模式中最為常見(jiàn)的幾個(gè)模式之一,是基于繼承的代碼復(fù)用的基本技術(shù)。

  模板方法模式需要開(kāi)發(fā)抽象類和具體子類的設(shè)計(jì)師之間的協(xié)作。一個(gè)設(shè)計(jì)師負(fù)責(zé)給出一個(gè)算法的輪廓和骨架,另一些設(shè)計(jì)師則負(fù)責(zé)給出這個(gè)算法的各個(gè)邏輯步驟。代表這些具體邏輯步驟的方法稱做基本方法(primitive method);而將這些基本方法匯總起來(lái)的方法叫做模板方法(template method),這個(gè)設(shè)計(jì)模式的名字就是從此而來(lái)。

  模板方法所代表的行為稱為頂級(jí)行為,其邏輯稱為頂級(jí)邏輯。模板方法模式的靜態(tài)結(jié)構(gòu)圖如下所示:

  

  這里涉及到兩個(gè)角色:

  抽象模板(Abstract Template)角色有如下責(zé)任:

  ■  定義了一個(gè)或多個(gè)抽象操作,以便讓子類實(shí)現(xiàn)。這些抽象操作叫做基本操作,它們是一個(gè)頂級(jí)邏輯的組成步驟。

  ■  定義并實(shí)現(xiàn)了一個(gè)模板方法。這個(gè)模板方法一般是一個(gè)具體方法,它給出了一個(gè)頂級(jí)邏輯的骨架,而邏輯的組成步驟在相應(yīng)的抽象操作中,推遲到子類實(shí)現(xiàn)。頂級(jí)邏輯也有可能調(diào)用一些具體方法。

  具體模板(Concrete Template)角色又如下責(zé)任:

  ■  實(shí)現(xiàn)父類所定義的一個(gè)或多個(gè)抽象方法,它們是一個(gè)頂級(jí)邏輯的組成步驟。

  ■  每一個(gè)抽象模板角色都可以有任意多個(gè)具體模板角色與之對(duì)應(yīng),而每一個(gè)具體模板角色都可以給出這些抽象方法(也就是頂級(jí)邏輯的組成步驟)的不同實(shí)現(xiàn),從而使得頂級(jí)邏輯的實(shí)現(xiàn)各不相同。

  源代碼

  抽象模板角色類,abstractMethod()、hookMethod()等基本方法是頂級(jí)邏輯的組成步驟,這個(gè)頂級(jí)邏輯由templateMethod()方法代表。

public abstract class AbstractTemplate {/*** 模板方法*/public void templateMethod(){//調(diào)用基本方法 abstractMethod();hookMethod();concreteMethod();}/*** 基本方法的聲明(由子類實(shí)現(xiàn))*/protected abstract void abstractMethod();/*** 基本方法(空方法)*/protected void hookMethod(){}/*** 基本方法(已經(jīng)實(shí)現(xiàn))*/private final void concreteMethod(){//業(yè)務(wù)相關(guān)的代碼 } }

  具體模板角色類,實(shí)現(xiàn)了父類所聲明的基本方法,abstractMethod()方法所代表的就是強(qiáng)制子類實(shí)現(xiàn)的剩余邏輯,而hookMethod()方法是可選擇實(shí)現(xiàn)的邏輯,不是必須實(shí)現(xiàn)的。

public class ConcreteTemplate extends AbstractTemplate{//基本方法的實(shí)現(xiàn) @Overridepublic void abstractMethod() {//業(yè)務(wù)相關(guān)的代碼 }//重寫(xiě)父類的方法 @Overridepublic void hookMethod() {//業(yè)務(wù)相關(guān)的代碼 } }

  模板模式的關(guān)鍵是:子類可以置換掉父類的可變部分,但是子類卻不可以改變模板方法所代表的頂級(jí)邏輯。

  每當(dāng)定義一個(gè)新的子類時(shí),不要按照控制流程的思路去想,而應(yīng)當(dāng)按照“責(zé)任”的思路去想。換言之,應(yīng)當(dāng)考慮哪些操作是必須置換掉的,哪些操作是可以置換掉的,以及哪些操作是不可以置換掉的。使用模板模式可以使這些責(zé)任變得清晰。

模板方法模式中的方法

  模板方法中的方法可以分為兩大類:模板方法和基本方法。

  模板方法

  一個(gè)模板方法是定義在抽象類中的,把基本操作方法組合在一起形成一個(gè)總算法或一個(gè)總行為的方法。

  一個(gè)抽象類可以有任意多個(gè)模板方法,而不限于一個(gè)。每一個(gè)模板方法都可以調(diào)用任意多個(gè)具體方法。

  基本方法

  基本方法又可以分為三種:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。

  ●  抽象方法:一個(gè)抽象方法由抽象類聲明,由具體子類實(shí)現(xiàn)。在Java語(yǔ)言里抽象方法以abstract關(guān)鍵字標(biāo)示。

  ●  具體方法:一個(gè)具體方法由抽象類聲明并實(shí)現(xiàn),而子類并不實(shí)現(xiàn)或置換。

  ●  鉤子方法:一個(gè)鉤子方法由抽象類聲明并實(shí)現(xiàn),而子類會(huì)加以擴(kuò)展。通常抽象類給出的實(shí)現(xiàn)是一個(gè)空實(shí)現(xiàn),作為方法的默認(rèn)實(shí)現(xiàn)。

  在上面的例子中,AbstractTemplate是一個(gè)抽象類,它帶有三個(gè)方法。其中abstractMethod()是一個(gè)抽象方法,它由抽象類聲明為抽象方法,并由子類實(shí)現(xiàn);hookMethod()是一個(gè)鉤子方法,它由抽象類聲明并提供默認(rèn)實(shí)現(xiàn),并且由子類置換掉。concreteMethod()是一個(gè)具體方法,它由抽象類聲明并實(shí)現(xiàn)。

  默認(rèn)鉤子方法

  一個(gè)鉤子方法常常由抽象類給出一個(gè)空實(shí)現(xiàn)作為此方法的默認(rèn)實(shí)現(xiàn)。這種空的鉤子方法叫做“Do Nothing Hook”。顯然,這種默認(rèn)鉤子方法在缺省適配模式里面已經(jīng)見(jiàn)過(guò)了,一個(gè)缺省適配模式講的是一個(gè)類為一個(gè)接口提供一個(gè)默認(rèn)的空實(shí)現(xiàn),從而使得缺省適配類的子類不必像實(shí)現(xiàn)接口那樣必須給出所有方法的實(shí)現(xiàn),因?yàn)橥ǔR粋€(gè)具體類并不需要所有的方法。

  命名規(guī)則

  命名規(guī)則是設(shè)計(jì)師之間賴以溝通的管道之一,使用恰當(dāng)?shù)拿?guī)則可以幫助不同設(shè)計(jì)師之間的溝通。

  鉤子方法的名字應(yīng)當(dāng)以do開(kāi)始,這是熟悉設(shè)計(jì)模式的Java開(kāi)發(fā)人員的標(biāo)準(zhǔn)做法。在上面的例子中,鉤子方法hookMethod()應(yīng)當(dāng)以do開(kāi)頭;在HttpServlet類中,也遵從這一命名規(guī)則,如doGet()、doPost()等方法。

?


使用場(chǎng)景

  考慮一個(gè)計(jì)算存款利息的例子。假設(shè)系統(tǒng)需要支持兩種存款賬號(hào),即貨幣市場(chǎng)(Money Market)賬號(hào)和定期存款(Certificate of Deposite)賬號(hào)。這兩種賬號(hào)的存款利息是不同的,因此,在計(jì)算一個(gè)存戶的存款利息額時(shí),必須區(qū)分兩種不同的賬號(hào)類型。

  這個(gè)系統(tǒng)的總行為應(yīng)當(dāng)是計(jì)算出利息,這也就決定了作為一個(gè)模板方法模式的頂級(jí)邏輯應(yīng)當(dāng)是利息計(jì)算。由于利息計(jì)算涉及到兩個(gè)步驟:一個(gè)基本方法給出賬號(hào)種類,另一個(gè)基本方法給出利息百分比。這兩個(gè)基本方法構(gòu)成具體邏輯,因?yàn)橘~號(hào)的類型不同,所以具體邏輯會(huì)有所不同。

  顯然,系統(tǒng)需要一個(gè)抽象角色給出頂級(jí)行為的實(shí)現(xiàn),而將兩個(gè)作為細(xì)節(jié)步驟的基本方法留給具體子類實(shí)現(xiàn)。由于需要考慮的賬號(hào)有兩種:一是貨幣市場(chǎng)賬號(hào),二是定期存款賬號(hào)。系統(tǒng)的類結(jié)構(gòu)如下圖所示。

  源代碼

  抽象模板角色類

public abstract class Account {/*** 模板方法,計(jì)算利息數(shù)額* @return 返回利息數(shù)額*/public final double calculateInterest(){double interestRate = doCalculateInterestRate();String accountType = doCalculateAccountType();double amount = calculateAmount(accountType);return amount * interestRate;}/*** 基本方法留給子類實(shí)現(xiàn)*/protected abstract String doCalculateAccountType();/*** 基本方法留給子類實(shí)現(xiàn)*/protected abstract double doCalculateInterestRate();/*** 基本方法,已經(jīng)實(shí)現(xiàn)*/private double calculateAmount(String accountType){/*** 省略相關(guān)的業(yè)務(wù)邏輯*/return 7243.00;} }

  具體模板角色類

public class MoneyMarketAccount extends Account {@Overrideprotected String doCalculateAccountType() {return "Money Market";}@Overrideprotected double doCalculateInterestRate() {return 0.045;}} public class CDAccount extends Account {@Overrideprotected String doCalculateAccountType() {return "Certificate of Deposite";}@Overrideprotected double doCalculateInterestRate() {return 0.06;}}

客戶端類

public class Client {public static void main(String[] args) {Account account = new MoneyMarketAccount();System.out.println("貨幣市場(chǎng)賬號(hào)的利息數(shù)額為:" + account.calculateInterest());account = new CDAccount();System.out.println("定期賬號(hào)的利息數(shù)額為:" + account.calculateInterest());}}

?


模板方法模式在Servlet中的應(yīng)用

  使用過(guò)Servlet的人都清楚,除了要在web.xml做相應(yīng)的配置外,還需繼承一個(gè)叫HttpServlet的抽象類。HttpService類提供了一個(gè)service()方法,這個(gè)方法調(diào)用七個(gè)do方法中的一個(gè)或幾個(gè),完成對(duì)客戶端調(diào)用的響應(yīng)。這些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);}}

?

  當(dāng)然,這個(gè)service()方法也可以被子類置換掉。

  下面給出一個(gè)簡(jiǎn)單的Servlet例子:

    

  從上面的類圖可以看出,TestServlet類是HttpServlet類的子類,并且置換掉了父類的兩個(gè)方法: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");}}

?

  從上面的例子可以看出這是一個(gè)典型的模板方法模式。

  HttpServlet擔(dān)任抽象模板角色

    模板方法:由service()方法擔(dān)任。

    基本方法:由doPost()、doGet()等方法擔(dān)任。

  TestServlet擔(dān)任具體模板角色

    TestServlet置換掉了父類HttpServlet中七個(gè)基本方法中的其中兩個(gè),分別是doGet()和doPost()。


總結(jié)

以上是生活随笔為你收集整理的《JAVA与模式》之模板方法模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。