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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

设计模式(5)----模板方法

發(fā)布時間:2023/12/20 asp.net 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 设计模式(5)----模板方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

模板方法

原文地址1

原文地址2

一、模板方法模式的定義

???? 模板方法模式(TemplateMethod Pattern)其定義如下:

???? Define theskeleton of an algorithm in an operation, deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm withoutchanging the algorithm's structure。

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

?

通常我們會遇到這樣的一個問題:我們知道一個算法所需的關鍵步驟,并確定了這些步驟的執(zhí)行順序。但是某些步驟的具體實現(xiàn)是未知的,或者說某些步驟的實現(xiàn)與具體的環(huán)境相關。模板方法模式把我們不知道具體實現(xiàn)的步驟封裝成抽象方法,提供一個按正確順序調用它們的具體方法(這些具體方法統(tǒng)稱為模板方法”),這樣構成一個抽象基類。子類通過繼承這個抽象基類去實現(xiàn)各個步驟的抽象方法,而工作流程卻由父類控制。

二、引入例子

生產(chǎn)悍馬車,悍馬車有兩個型號,H1和H2,

抽象悍馬模型????

在抽象類中,我們定義了悍馬模型都必須具有的特質:能夠啟動、停止,喇叭會響,引擎可以轟鳴,

public abstract class HummerModel {public abstract void start();public abstract void stop();public abstract void alarm();public abstract void engineBoom();public abstract void run();}

H1型號悍馬模型

public class HummerH1Model extends HummerModel {//H1型號的悍馬車鳴笛public void alarm() {System.out.println("悍馬H1鳴笛...");}//引擎轟鳴聲public void engineBoom() {System.out.println("悍馬H1引擎聲音是這樣在...");}//汽車發(fā)動public void start() {System.out.println("悍馬H1發(fā)動...");}//停車public void stop() {System.out.println("悍馬H1停車...");}//開動起來public void run() {//先發(fā)動汽車this.start();//引擎開始轟鳴this.engineBoom();//然后就開始跑了,跑的過程中遇到一條狗擋路,就按喇叭this.alarm();//到達目的地就停車this.stop();}}

H2型號悍馬模型

public class HummerH2Model extends HummerModel {//H2型號的悍馬車鳴笛public void alarm() {System.out.println("悍馬H2鳴笛...");}//引擎轟鳴聲public void engineBoom() {System.out.println("悍馬H2引擎聲音是這樣在...");}//汽車發(fā)動public void start() {System.out.println("悍馬H2發(fā)動...");}//停車public void stop() {System.out.println("悍馬H2停車...");}//開動起來public void run() {//先發(fā)動汽車this.start();//引擎開始轟鳴this.engineBoom();//然后就開始跑了,跑的過程中遇到一條狗擋路,就按喇叭this.alarm();//到達目的地就停車this.stop();}}

程序編寫到這里,已經(jīng)發(fā)現(xiàn)問題了,兩個實現(xiàn)類的run()方法都是完全相同的,那這個run()方法的實現(xiàn)應該出現(xiàn)在抽象類,不應該在實現(xiàn)類上,抽象是所有子類的共性封裝。

注意在軟件開發(fā)過程中,如果相同的一段代碼拷貝過兩次,就需要對設計產(chǎn)生懷疑,架構師要明確的說明為什么相同的邏輯要出現(xiàn)兩次或更多次。

應用模板方法修改悍馬模型

public abstract class HummerModel {public abstract void start();public abstract void stop();public abstract void alarm();public abstract void engineBoom();public void run() {//先發(fā)動汽車this.start();//引擎開始轟鳴this.engineBoom();//然后就開始跑了,跑的過程中遇到一條狗擋路,就按喇叭this.alarm();//到達目的地就停車this.stop();}}

抽象的悍馬模型上已經(jīng)定義了run方法的執(zhí)行規(guī)則,先啟動,然后引擎立刻轟鳴,中間還要按一下喇叭,制造點噪聲(要不就不是名車了),然后停車,它的兩個具體實現(xiàn)類就不需要實現(xiàn)run方法了

場景類

public class Client {public static void main(String[] args) {//H1型號的悍馬HummerModel h1 = new HummerH1Model();//H1模型演示h1.run();}}

三、結構和通用代碼

3.1、結構

準備一個抽象類,定義一個操作中的算法的骨架,將一些步驟聲明為抽象方法迫使子類去實現(xiàn)。不同的子類可以以不同的方式實現(xiàn)這些抽象方法。模板模式的關鍵是:子類可以置換掉父類的可變部分,但是子類卻不可以改變模板方法所代表的頂級邏輯。

抽象模板

模板方法模式確實非常簡單,僅僅使用了Java的繼承機制,但是它是一個應用非常廣泛的模式。其中,AbstractClass叫做抽象模板,它的方法分為兩類:

  • 基本方法 基本方法也叫做基本操作,是由子類實現(xiàn)的方法,并且在模板方法被調用。

  • 模板方法 可以有一個或幾個,一般是一個具體方法,也就是一個骨架,實現(xiàn)對基本方法的調度,完成固定的邏輯。注意為了防止惡意的操作,一般模板方法都加上final關鍵字,不允許被覆寫。

具體模板

???? 在類圖中還有一個角色:具體模板,ConcreteClass1和ConcreteClass2屬于具體模板,實現(xiàn)父類所定義的一個或多個抽象方法,也就是父類定義的基本方法在子類中得以實現(xiàn)。

3.2、通用代碼

AbstractClass

public abstract class AbstractClass {//基本方法protected abstract void doSomething();//基本方法protected abstract void doAnything();//模板方法public void templateMethod() {/** 調用基本方法,完成相關的邏輯*/this.doAnything();this.doSomething();}}

ConcreteClass1

public class ConcreteClass1 extends AbstractClass {//實現(xiàn)基本方法protected void doAnything() {//業(yè)務邏輯處理}protected void doSomething() {//業(yè)務邏輯處理}}

ConcreteClass2

public class ConcreteClass2 extends AbstractClass {//實現(xiàn)基本方法protected void doAnything() {//業(yè)務邏輯處理}protected void doSomething() {//業(yè)務邏輯處理}}

場景類

public class Client {public static void main(String[] args) {AbstractClass class1 = new ConcreteClass1();AbstractClass class2 = new ConcreteClass2();//調用模板方法class1.templateMethod();class2.templateMethod();}}

?

四、模板方法模式的應用

1. 模板方法模式的優(yōu)點

  • 封裝不變部分,擴展可變部分。

???? 把認為是不變部分的算法封裝到父類實現(xiàn),而可變部分的則可以通過繼承來繼續(xù)擴展。我們悍馬模型例子中,是不是就非常容易擴展,例如增加一個H3型號的悍馬模型,很容易呀,增加一個子類,實現(xiàn)父類的基本方法就可以了。

  • 提取公共部分代碼,便于維護。

???? 我們例子中剛剛走過的彎路就是最好的證明,如果我們不抽取到父類中,任由這種散亂的代碼發(fā)生,想想后果是什么樣子?維護人員為了修正一個缺陷,需要到處查找類似的代碼!

  • 行為控制交由子類來實現(xiàn)。

???? 基本方法是由子類實現(xiàn)的,因此子類可以通過擴展的方式增加相應的功能,符合開閉原則。

2. 模板方法模式的缺點

???? 按照我們設計習慣,抽象類負責聲明最抽象、最一般的事物屬性和方法,實現(xiàn)類完成具體的事物屬性和方法,但是模板方法模式卻顛倒了,抽象類定義了部分抽象方法,由子類實現(xiàn),子類執(zhí)行的結果影響了父類的結果,也就是子類對父類產(chǎn)生了影響,這在復雜的項目中,會帶來代碼閱讀的難度,而且也會讓新手產(chǎn)生不適感。

3. 模板方法模式的使用場景

    • 多個子類有公有的方法,并且邏輯基本相同時。
    • 重要、復雜的算法,可以把核心算法設計為模板方法,周邊的相關細節(jié)功能則由各個子類實現(xiàn)。
    • 重構時,模板方法模式是一個經(jīng)常使用的模式,把相同的代碼抽取到父類中,然后通過鉤子函數(shù)(見“模板方法模式的擴展”)約束其行為。

4.板方法模式與對象的封裝性

注意抽象模版中的基本方法盡量設計為protected類型,符合迪米特原則,不需要暴露的屬性或方法盡量不要設置為protected類型。實現(xiàn)類若非必要,盡量不要擴大父類中訪問權限。

五、框架中的應用

模板方法在一些開源框架中應用非常很多,它提供了一個抽象類,然后開源框架寫了一堆子類,在《XXX In Action》中就說明了,如果你需要擴展功能,可以繼承了這個抽象類,然后覆寫protected方法,再然后就是調用一個類似execute方法,就完成你的擴展開發(fā),非常容易擴展的一種模式

1 JUnit中的TestCase以及它的子類就是一個模板方法模式的例子。在TestCase這個抽象類中將整個測試的流程設置好,比如先執(zhí)行setup方法初始化測試資源,再運行測試方法,然后再tearDown來釋放測試資源。但是我們將在setuptearDown里面作些什么?誰知道呢?!因此,這些步驟的具體實現(xiàn)都會延遲到子類中去,也就是我們實現(xiàn)的測試類中。

2 Struts框架控制器的核心類RequestProcess里面的process方法也是采用了經(jīng)典的模板方法模式,里面定義好了流程的步驟,而步驟里面的很多環(huán)節(jié),我們都是可以重寫的。

3模板方法模式在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 logicdoGet(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 lessmaybeSetLastModified(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);}}

下面給出一個簡單的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()。

六、帶鉤子函數(shù)的模板方法的引入

客戶提出H1型號的悍馬喇叭想讓它響就響,H2型號的喇叭不要有聲音。

類圖似乎改動很小,在抽象類HummerModel中增加了一個實現(xiàn)方法isAlarm,確定各個型號的悍馬是否需要聲音,由各個實現(xiàn)類覆寫該方法,

修改后的悍馬模型

public abstract class HummerModel {protected abstract void start();protected abstract void stop();protected abstract void alarm();protected abstract void engineBoom();final public void run() {// 先發(fā)動汽車this.start();// 引擎開始轟鳴this.engineBoom();// 要讓它叫的就是就叫,喇嘛不想讓它響就不響if (this.isAlarm()) {this.alarm();}// 到達目的地就停車this.stop();}// 鉤子方法,默認喇叭是會響的protected boolean isAlarm() {return true;}}

在抽象類中,isAlarm是一個實現(xiàn)方法,其作用是模板方法根據(jù)其返回值決定是否要響喇叭,子類可以覆寫該返回值,由于H1型號的喇叭是想讓它響就響,不想讓它響就不響,由人控制了

public class HummerH1Model extends HummerModel {private boolean alarmFlag = true; //要響喇叭protected void alarm() {System.out.println("悍馬H1鳴笛...");}protected void engineBoom() {System.out.println("悍馬H1引擎聲音是這樣在...");}protected void start() {System.out.println("悍馬H1發(fā)動...");}protected void stop() {System.out.println("悍馬H1停車...");}protected boolean isAlarm() {return this.alarmFlag;}//要不要響喇叭,是有客戶的來決定的public void setAlarm(boolean isAlarm) {this.alarmFlag = isAlarm;}}

H2型號的悍馬是沒有喇叭聲響的

public class HummerH2Model extends HummerModel {protected void alarm() {System.out.println("悍馬H2鳴笛...");}protected void engineBoom() {System.out.println("悍馬H2引擎聲音是這樣在...");}protected void start() {System.out.println("悍馬H2發(fā)動...");}protected void stop() {System.out.println("悍馬H2停車...");}//默認沒有喇叭的protected boolean isAlarm() {return false;}}

Client

public class Client {public static void main(String[] args) throws IOException {System.out.println("-------H1型號悍馬--------");System.out.println("H1型號的悍馬是否需要喇叭聲響?0-不需要 1-需要");String type = (new BufferedReader(new InputStreamReader(System.in))).readLine();HummerH1Model h1 = new HummerH1Model();if (type.equals("0")) {h1.setAlarm(false);}h1.run();System.out.println("\n-------H2型號悍馬--------");HummerH2Model h2 = new HummerH2Model();h2.run();}}

H1型號的悍馬是由客戶自己控制是否要響喇叭,也就是說外界條件改變,影響到模板方法的執(zhí)行,在我們的抽象類中isAlarm的返回值就是影響了模板方法的執(zhí)行結果,該方法就叫做鉤子方法(Hook Method),有了鉤子方法模板方法模式才算完美,大家可以想想,由子類的一個方法返回值決定決定公共部分的執(zhí)行結果。

七、帶鉤子函數(shù)的模板方法的代碼框架

這里涉及到兩個角色:

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

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

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

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

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

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

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

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

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

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

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

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

模板方法模式中的方法

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

模板方法

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

  一個抽象類可以有任意多個模板方法,而不限于一個。每一個模板方法都可以調用任意多個具體方法。

基本方法

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

  ●抽象方法:一個抽象方法由抽象類聲明,由具體子類實現(xiàn)。在Java語言里抽象方法以abstract關鍵字標示。

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

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

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

  默認鉤子方法

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

  命名規(guī)則

  命名規(guī)則是設計師之間賴以溝通的管道之一,使用恰當?shù)拿?guī)則可以幫助不同設計師之間的溝通。鉤子方法的名字應當以do開始,這是熟悉設計模式的Java開發(fā)人員的標準做法。在上面的例子中,鉤子方法hookMethod()應當以do開頭;在HttpServlet類中,也遵從這一命名規(guī)則,如doGet()、doPost()等方法。


?

?

總結

以上是生活随笔為你收集整理的设计模式(5)----模板方法的全部內容,希望文章能夠幫你解決所遇到的問題。

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