模板方法模式 java

1. 模板方法模式概述

在現(xiàn)實(shí)生活中,很多事情都包含幾個實(shí)現(xiàn)步驟,例如請客吃飯,無論吃什么,一般都包含點(diǎn)單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點(diǎn)單 –> 吃東西 –> 買單。在這三個步驟中,點(diǎn)單和買單大同小異,最大的區(qū)別在于第二步——吃什么?吃面條和吃滿漢全席可大不相同,如圖所示:

在軟件開發(fā)中,有時也會遇到類似的情況,某個方法的實(shí)現(xiàn)需要多個步驟(類似“請客”),其中有些步驟是固定的(類似“點(diǎn)單”和“買單”),而有些步驟并不固定,存在可變性(類似“吃東西”)。為了提高代碼的復(fù)用性和系統(tǒng)的靈活性,可以使用一種稱之為模板方法模式的設(shè)計模式來對這類情況進(jìn)行設(shè)計,在模板方法模式中,將實(shí)現(xiàn)功能的每一個步驟所對應(yīng)的方法稱為基本方法(例如“點(diǎn)單”、“吃東西”和“買單”),而調(diào)用這些基本方法同時定義基本方法的執(zhí)行次序的方法稱為模板方法(例如“請客”)。在模板方法模式中,可以將相同的代碼放在父類中,例如將模板方法“請客”以及基本方法“點(diǎn)單”和“買單”的實(shí)現(xiàn)放在父類中,而對于基本方法“吃東西”,在父類中只做一個聲明,將其具體實(shí)現(xiàn)放在不同的子類中,在一個子類中提供“吃面條”的實(shí)現(xiàn),而另一個子類提供“吃滿漢全席”的實(shí)現(xiàn)。通過使用模板方法模式,一方面提高了代碼的復(fù)用性,另一方面還可以利用面向?qū)ο蟮亩鄳B(tài)性,在運(yùn)行時選擇一種具體子類,實(shí)現(xiàn)完整的“請客”方法,提高系統(tǒng)的靈活性和可擴(kuò)展性。

模板方法模式定義如下:

模板方法模式:定義一個操作中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

Template Method Pattern: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

模板方法模式是一種基于繼承的代碼復(fù)用技術(shù),它是一種類行為型模式。

模板方法模式是結(jié)構(gòu)最簡單的行為型設(shè)計模式,在其結(jié)構(gòu)中只存在父類與子類之間的繼承關(guān)系。通過使用模板方法模式,可以將一些復(fù)雜流程的實(shí)現(xiàn)步驟封裝在一系列基本方法中,在抽象父類中提供一個稱之為模板方法的方法來定義這些基本方法的執(zhí)行次序,而通過其子類來覆蓋某些步驟,從而使得相同的算法框架可以有不同的執(zhí)行結(jié)果。模板方法模式提供了一個模板方法來定義算法框架,而某些具體步驟的實(shí)現(xiàn)可以在其子類中完成。

2. 模板方法模式結(jié)構(gòu)與實(shí)現(xiàn)

2.1 模式結(jié)構(gòu)

模板方法模式結(jié)構(gòu)比較簡單,其核心是抽象類和其中的模板方法的設(shè)計,其結(jié)構(gòu)如圖2所示:

由圖可知,模板方法模式包含如下兩個角色:

(1) AbstractClass(抽象類):在抽象類中定義了一系列基本操作(PrimitiveOperations),這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應(yīng)算法的一個步驟,在其子類中可以重定義或?qū)崿F(xiàn)這些步驟。同時,在抽象類中實(shí)現(xiàn)了一個模板方法(Template Method),用于定義一個算法的框架,模板方法不僅可以調(diào)用在抽象類中實(shí)現(xiàn)的基本方法,也可以調(diào)用在抽象類的子類中實(shí)現(xiàn)的基本方法,還可以調(diào)用其他對象中的方法。

(2) ConcreteClass(具體子類):它是抽象類的子類,用于實(shí)現(xiàn)在父類中聲明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經(jīng)實(shí)現(xiàn)的具體基本操作。

2.2 模式實(shí)現(xiàn)

在實(shí)現(xiàn)模板方法模式時,開發(fā)抽象類的軟件設(shè)計師和開發(fā)具體子類的軟件設(shè)計師之間可以進(jìn)行協(xié)作。一個設(shè)計師負(fù)責(zé)給出一個算法的輪廓和框架,另一些設(shè)計師則負(fù)責(zé)給出這個算法的各個邏輯步驟。實(shí)現(xiàn)這些具體邏輯步驟的方法即為基本方法,而將這些基本方法匯總起來的方法即為模板方法,模板方法模式的名字也因此而來。下面將詳細(xì)介紹模板方法和基本方法:

  1. 模板方法

一個模板方法是定義在抽象類中的、把基本操作方法組合在一起形成一個總算法或一個總行為的方法。這個模板方法定義在抽象類中,并由子類不加以修改地完全繼承下來。模板方法是一個具體方法,它給出了一個頂層邏輯框架,而邏輯的組成步驟在抽象類中可以是具體方法,也可以是抽象方法。由于模板方法是具體方法,因此模板方法模式中的抽象層只能是抽象類,而不是接口。

  1. 基本方法

基本方法是實(shí)現(xiàn)算法各個步驟的方法,是模板方法的組成部分?;痉椒ㄓ挚梢苑譃槿N:抽象方法(Abstract Method)、具體方法(Concrete Method)和鉤子方法(Hook Method)。
(1) 抽象方法:一個抽象方法由抽象類聲明、由其具體子類實(shí)現(xiàn)。在C#語言里一個抽象方法以abstract關(guān)鍵字標(biāo)識。

(2) 具體方法:一個具體方法由一個抽象類或具體類聲明并實(shí)現(xiàn),其子類可以進(jìn)行覆蓋也可以直接繼承。

(3) 鉤子方法:一個鉤子方法由一個抽象類或具體類聲明并實(shí)現(xiàn),而其子類可能會加以擴(kuò)展。通常在父類中給出的實(shí)現(xiàn)是一個空實(shí)現(xiàn)(可使用virtual關(guān)鍵字將其定義為虛函數(shù)),并以該空實(shí)現(xiàn)作為方法的默認(rèn)實(shí)現(xiàn),當(dāng)然鉤子方法也可以提供一個非空的默認(rèn)實(shí)現(xiàn)。

在模板方法模式中,鉤子方法有兩類:第一類鉤子方法可以與一些具體步驟“掛鉤”,以實(shí)現(xiàn)在不同條件下執(zhí)行模板方法中的不同步驟,這類鉤子方法的返回類型通常是bool類型的,這類方法名一般為IsXXX(),用于對某個條件進(jìn)行判斷,如果條件滿足則執(zhí)行某一步驟,否則將不執(zhí)行,如下代碼片段所示:

……  
//模板方法  
public void TemplateMethod()   
{  
Open();  
Display();  
//通過鉤子方法來確定某步驟是否執(zhí)行  
if (IsPrint())   
{  
    Print();  
}  
}  
  
//鉤子方法  
public bool IsPrint()  
{  
    return true;  
}  
……  

在代碼中IsPrint()方法即是鉤子方法,它可以決定Print()方法是否執(zhí)行,一般情況下,鉤子方法的返回值為true,如果不希望某方法執(zhí)行,可以在其子類中覆蓋鉤子方法,將其返回值改為false即可,這種類型的鉤子方法可以控制方法的執(zhí)行,對一個算法進(jìn)行約束。

還有一類鉤子方法就是實(shí)現(xiàn)體為空的具體方法,子類可以根據(jù)需要覆蓋或者繼承這些鉤子方法,與抽象方法相比,這類鉤子方法的好處在于子類如果沒有覆蓋父類中定義的鉤子方法,編譯可以正常通過,但是如果沒有覆蓋父類中聲明的抽象方法,編譯將報錯。

在模板方法模式中,抽象類的典型代碼如下:

abstract class AbstractClass 
{
//模板方法
public void TemplateMethod() 
{
        PrimitiveOperation1();
        PrimitiveOperation2();
        PrimitiveOperation3();
}

//基本方法—具體方法
public void PrimitiveOperation1() 
{
    //實(shí)現(xiàn)代碼
}

//基本方法—抽象方法
    public abstract void PrimitiveOperation2();    

//基本方法—鉤子方法
public virtual void PrimitiveOperation3()   
{  }
}

在抽象類中,模板方法TemplateMethod()定義了算法的框架,在模板方法中調(diào)用基本方法以實(shí)現(xiàn)完整的算法,每一個基本方法如PrimitiveOperation1()、PrimitiveOperation2()等均實(shí)現(xiàn)了算法的一部分,對于所有子類都相同的基本方法可在父類提供具體實(shí)現(xiàn),例如PrimitiveOperation1(),否則在父類聲明為抽象方法或鉤子方法,由不同的子類提供不同的實(shí)現(xiàn),例如PrimitiveOperation2()和PrimitiveOperation3()。

可在抽象類的子類中提供抽象步驟的實(shí)現(xiàn),也可覆蓋父類中已經(jīng)實(shí)現(xiàn)的具體方法,具體子類的典型代碼如下:

class ConcreteClass : AbstractClass 
{
public override void PrimitiveOperation2() 
{
    //實(shí)現(xiàn)代碼
}

public override void PrimitiveOperation3() 
{
    //實(shí)現(xiàn)代碼
}
}

在模板方法模式中,由于面向?qū)ο蟮亩鄳B(tài)性,子類對象在運(yùn)行時將覆蓋父類對象,子類中定義的方法也將覆蓋父類中定義的方法,因此程序在運(yùn)行時,具體子類的基本方法將覆蓋父類中定義的基本方法,子類的鉤子方法也將覆蓋父類的鉤子方法,從而可以通過在子類中實(shí)現(xiàn)的鉤子方法對父類方法的執(zhí)行進(jìn)行約束,實(shí)現(xiàn)子類對父類行為的反向控制。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容