設(shè)計模式-模版方法模式

設(shè)計模式-模版方法模式

定義

模版方法模式(Template Method Pattern)又叫模版模式,是指定義一個操作中的算法的框架,而將一些步驟延遲到子類中.使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟,屬于行為型設(shè)計模式.

模版方法模式實際上是封裝了一個固定流程,該流程由幾個步驟組成,具體步驟可以由子類進行不同實現(xiàn),從而讓固定的流程產(chǎn)生不同的結(jié)果.它非常簡單,其實就是類的繼承機制,但它卻是一個應(yīng)用非常廣泛的模式.模版模式的本質(zhì)抽象封裝流程,具體進行實現(xiàn).

模版方法模式的應(yīng)用場景

當(dāng)一個操作具有固定的流程時,由抽象固定流程步驟,具體步驟交給子類進行具體實現(xiàn)(固定的流程,不同的實現(xiàn)).

在我們的日常生活當(dāng)中,模版方法非常的常見.比如以下流程:

辦理入職流程可以使用模版模式
再比如炒菜流程

再比如趙本山老師的經(jīng)典小品中的一個段子,把大象放進冰箱需要幾步?

把大象放進冰箱需要3步O.o

那么,同學(xué)們,我們接著研究一下:把長頸鹿放進冰箱需要幾步?還是3步嗎?

-

-

-

-

-

哈哈,這次需要4步~~至于為什么不一樣了,后續(xù)我們會講到鉤子方法...

從以上的案例中,我們不難總結(jié)出模版方法模式的適用場景:

1、一次性實現(xiàn)一個算法的不變的部分,并將可變的行為留給子類來實現(xiàn).

2、各子類中公公的行為被提取出來并集中到一個公共的父類中,從而避免代碼重復(fù).

首先,我們看一下模版方法的通用UML靜態(tài)類圖:

通用靜態(tài)類圖

在UML類圖中,我們不難看到,模版方法模式主要包含兩種角色:

抽象模版(AbstractClass):抽象模版類,定義了一套算法框架/流程;

具體實現(xiàn)(ConcreteClass):具體實現(xiàn)類,對算法框架/流程中的某些步驟進行了實現(xiàn).

模版方法模式中的鉤子方法

我們繼續(xù)以趙本山老師的冰箱裝大象事件為例,通過代碼來實現(xiàn):

創(chuàng)建抽象模板類

抽象模板類中有個鉤子方法,這里解釋一下.設(shè)計鉤子方法的主要目的用來干預(yù)執(zhí)行流程,使得我們能夠控制執(zhí)行流程,是其更符合實際業(yè)務(wù)需求.鉤子方法的返回值一般為適合條件分支語句的返回值(如:boolean、int等).小伙伴們可以根據(jù)自己的實際業(yè)務(wù)場景決定是否使用鉤子方法.

裝大象實現(xiàn)類
裝長頸鹿實現(xiàn)類
測試方法
運行結(jié)果
冰箱裝大象的UML類圖

通過這個案例,相信小伙伴們一定對模版方法及鉤子方法有了一個初步的認(rèn)識.為了加深理解,我們一起去探查另一個應(yīng)用案例.

利用模版方法模式重構(gòu)JDBC操作業(yè)務(wù)場景

創(chuàng)建一個模版累JdbcTemplate,封裝所有的JDBC操作.以查詢?yōu)槔?每次查詢的表不同,返回的數(shù)據(jù)結(jié)構(gòu)也不一樣.我們針對不同的數(shù)據(jù),都要封裝成不同的實體對象.而每個實體封裝的邏輯都是不一樣的,但封裝前和封裝后的處理流程是不變的,因此,我們可以使用模版方法模式來設(shè)計這樣的業(yè)務(wù)場景.先創(chuàng)建約束ORM邏輯的接口RowMapper:

接口RowMappe

再創(chuàng)建封裝了所有處理流程的抽象類JdbcTemplate:

抽象類JdbcTemplate
實體對象Member
數(shù)據(jù)庫操作類MemberDao
測試方法

希望通過以上兩個案例的業(yè)務(wù)場景分析,能夠幫助小伙伴們對模版方法模式有比較深入的理解.

模版方法模式在源碼中的應(yīng)用

先來看JDK中的AbstractList,來看代碼:

抽象類AbstractList

我們看到get()是一個抽象方法,那么它的邏輯就是交給子類來實現(xiàn),我們大家熟悉的ArrayList就是AbstractList的子類.同理,有AbstractList就有AbstractSet和AbstractMap,感興趣的小伙伴們可以去看看這些的源碼實現(xiàn).還有一個每天都在用的HttpServlet,有3個方法:service()方法、doGet()方法和doPost()方法,都是模版方法的抽象實現(xiàn).

在Mybatis框架也有一些經(jīng)典的應(yīng)用,我們來看一下BaseExecutor類,它是一個基礎(chǔ)的SQL執(zhí)行類,實現(xiàn)了大部分的SQL執(zhí)行邏輯,然后把幾個方法教給子類定制化完成,源碼如下:

抽象類BaseExecutor

如:doUpdate()、doFlushStatements()、doQuery()、doQueryCursor()這幾個方法就是由子類來實現(xiàn)的,那么BaseExecutor有哪些子類呢?我們來看一下它的類圖:

BaseExecutor靜態(tài)類圖

我們再來看一下SimpleExecutor的doUpdate實現(xiàn):

SimpleExecutor的doUpdate實現(xiàn)

再來對比一下BatchExecutor的doUpdate實現(xiàn):

BatchExecutor的doUpdate實現(xiàn)

通過對比,我們不難發(fā)現(xiàn)兩者的差異.封裝抽象流程,具體進行實現(xiàn).感興趣的小伙伴可以繼續(xù)深入研究一波MyBatis源碼,我們這里就不繼續(xù)深挖啦.

模版方法模式的優(yōu)點

1、利用模版方法將相同處理邏輯的代碼放到抽象父類中,可以提高代碼的復(fù)用性.

2、在不同的子類中,通過對子類的擴展增加新的行為,提高代碼的擴展性.

3、把不變的行為寫在父類中,去除子類的重復(fù)代碼,提供了一個很好的代碼復(fù)用平臺,符合開閉原則.

模版方法模式的缺點

1、類數(shù)目增加,每個抽象類都需要至少一個子類來實現(xiàn),這樣導(dǎo)致類的數(shù)量增加.

2、類數(shù)量的增加,間接地增加了系統(tǒng)實現(xiàn)的復(fù)雜度.

3、繼承關(guān)系自身缺點,如果父類添加新的抽象方法,所有子類都要改一遍.

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

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

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