設(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)典小品中的一個段子,把大象放進冰箱需要幾步?

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

從以上的案例中,我們不難總結(jié)出模版方法模式的適用場景:
1、一次性實現(xiàn)一個算法的不變的部分,并將可變的行為留給子類來實現(xiàn).
2、各子類中公公的行為被提取出來并集中到一個公共的父類中,從而避免代碼重復(fù).
首先,我們看一下模版方法的通用UML靜態(tài)類圖:

在UML類圖中,我們不難看到,模版方法模式主要包含兩種角色:
抽象模版(AbstractClass):抽象模版類,定義了一套算法框架/流程;
具體實現(xiàn)(ConcreteClass):具體實現(xiàn)類,對算法框架/流程中的某些步驟進行了實現(xiàn).
模版方法模式中的鉤子方法
我們繼續(xù)以趙本山老師的冰箱裝大象事件為例,通過代碼來實現(xiàn):

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





通過這個案例,相信小伙伴們一定對模版方法及鉤子方法有了一個初步的認(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:

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




希望通過以上兩個案例的業(yè)務(wù)場景分析,能夠幫助小伙伴們對模版方法模式有比較深入的理解.
模版方法模式在源碼中的應(yīng)用
先來看JDK中的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í)行邏輯,然后把幾個方法教給子類定制化完成,源碼如下:

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

我們再來看一下SimpleExecutor的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)系自身缺點,如果父類添加新的抽象方法,所有子類都要改一遍.