模板模式:一種體現(xiàn)多態(tài)的設(shè)計(jì)模式

點(diǎn)擊上方「藍(lán)字」關(guān)注我們

0x01:模板模式
模板模式(Template),又叫模板方法模式(Template Method),在一個抽象類公開定義了執(zhí)行它的方法的模板。它的子類可以按需重寫方法實(shí)現(xiàn),但調(diào)用將以抽象類中定義的方式進(jìn)行。模板方法模式:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中,使得子類可以不改變一個算法的結(jié)構(gòu),就可以重定義該算法的某些特定步驟。UML類圖如下:

?主要包含如下角色:
AbstractClass(抽象模板類):在抽象類中定義了一系列基本操作,這些基本操作可以是具體的,也可以是抽象的,每一個基本操作對應(yīng)算法的一個步驟,在其子類中可以重定義或?qū)崿F(xiàn)這些步驟。同時,在抽象類中實(shí)現(xiàn)了一個模板方法(Template Method),用于定義一個算法的框架,模板方法不僅可以調(diào)用在抽象類中實(shí)現(xiàn)的基本方法,也可以調(diào)用在抽象類的子類中實(shí)現(xiàn)的基本方法,還可以調(diào)用其他對象中的方法。
ConcreteCalss(具體模板子類):它是抽象類的子類,用于實(shí)現(xiàn)在父類中聲明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經(jīng)實(shí)現(xiàn)的具體基本操作。
抽象模板類:定義一個模板方法來組合sing()和dance()兩個方法形成一個算法,然后讓子類重定義這兩個方法。
public?abstract?class?AbstractClass?{
????public?abstract?void?sing(String?name);
????public?abstract?void?dance(String?name);
????public?void?templateMethd(String?name)?{
????????sing(name);
????????dance(name);
????}
}
具體模板類:這里定義兩個具體模板類,ConcreteClassLiMing及ConcreteClassLiuDeHua來進(jìn)行測試,繼承抽象模板類,實(shí)現(xiàn)具體方法。
public?class?ConcreteClassLiMing?extends?AbstractClass?{
????@Override
????public?void?sing(String?name)?{
????????System.out.println(name?+?"在唱歌");
????}
????@Override
????public?void?dance(String?name)?{
????????System.out.println(name?+?"在跳舞");
????}
}
public?class?ConcreteClassLiuDeHua?extends?AbstractClass?{
????@Override
????public?void?sing(String?name)?{
????????System.out.println(name?+?"在唱歌");
????}
????@Override
????public?void?dance(String?name)?{
????????System.out.println(name?+?"在跳舞");
????}
}
Client客戶端:
public?class?Client?{
????public?static?void?main(String[]?args)?{
????????AbstractClass?abstractClass?=?null;
????????abstractClass?=?new?ConcreteClassLiMing();
????????abstractClass.templateMethd("黎明");
????????abstractClass?=?new?ConcreteClassLiuDeHua();
????????abstractClass.templateMethd("劉德華");
????}
}
通過以上代碼就實(shí)現(xiàn)了一個簡單的模板模式,模板模式的優(yōu)點(diǎn):封裝不變部分,擴(kuò)展可變部分。提取公共代碼,便于維護(hù)。行為由父類控制,子類實(shí)現(xiàn);缺點(diǎn):每一個不同的實(shí)現(xiàn)都需要一個子類來實(shí)現(xiàn),導(dǎo)致類的個數(shù)增加,使得系統(tǒng)更加龐大。
0x02:JDK中的模板模式
如果有了解過java.util.concurrent.locks包的AbstractQueuedSynchronizer類(簡稱AQS),就會發(fā)現(xiàn)AbstractQueuedSynchronizer類(同步器)是一個非常經(jīng)典的模板模式。如果需要自定義同步器,一般方法是:繼承AQS,并重寫指定方法(無非是按照自己定義的規(guī)則對state的獲取與釋放);將AQS組合在自定義同步組件的實(shí)現(xiàn)中,并調(diào)用模板方法,而這些模板方法會調(diào)用重寫的方法。
//該線程是否正在獨(dú)占資源。只有用到condition才需要去實(shí)現(xiàn)它。
isHeldExclusively();
//獨(dú)占方式。嘗試獲取資源,成功則返回true,失敗則返回false。
tryAcquire(int);
//獨(dú)占方式。嘗試釋放資源,成功則返回true,失敗則返回false。
tryRelease(int);
////共享方式。嘗試獲取資源。負(fù)數(shù)表示失敗;0表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。
tryAcquireShared(int);
////共享方式。嘗試釋放資源,成功則返回true,失敗則返回false。
tryReleaseShared(int);
默認(rèn)情況下,以上這些方法都拋出 UnsupportedOperationException。這些方法的實(shí)現(xiàn)必須是內(nèi)部線程安全的,并且通常應(yīng)該簡短而不是阻塞。AQS類中的其他方法都是final ,所以無法被其他類使用,只有這幾個方法可以被其他類使用。
0x03:Spring中的模板模式
Spring作為一個特優(yōu)秀的框架,底層大量使用模板模式。以Spring的事務(wù)管理器來講下Spring中的模板模式。
AbstractPlatformTransactionManager是Spring中的模板抽象類,它的繼承關(guān)系圖如下:

實(shí)現(xiàn)了PlatformTransactionManager接口,重載了接口中的方法。
模板方法:事務(wù)管理器中抽象類中的模板方法不止一個,比如以下兩個方法
//提交事務(wù)
public?final?void?commit()
//獲取TransactionStatus
public?final?TransactionStatus?getTransaction()
這兩個方法都對于自己要實(shí)現(xiàn)的邏輯搭建了一個骨架,主要的功能是由抽象方法完成,由子類來完成。
抽象方法:事務(wù)管理器抽象類中的抽象方法定義了多個,分別用于處理不同的業(yè)務(wù)邏輯,由子類實(shí)現(xiàn)其中具體的邏輯。
//提交事務(wù)
protected?abstract?void?doCommit(DefaultTransactionStatus?status);
//回滾事務(wù)
protected?abstract?void?doRollback(DefaultTransactionStatus?status);
//開始事務(wù)
protected?abstract?void?doBegin(Object?transaction,?TransactionDefinition?definition)
//獲取當(dāng)前的事務(wù)對象
protected?abstract?Object?doGetTransaction()
抽象方法的定義便于子類去擴(kuò)展,在保證算法邏輯不變的情況下,子類能夠定制自己的實(shí)現(xiàn)。
具體子類:其中有DataSourceTransactionManager、JtaTransactionManager、RabbitTransactionManager等,類繼承關(guān)系如下:

另外還有JdbcTemplate、JpaTemplate等使用了模板模式。其他需要大家慢慢去發(fā)現(xiàn),去學(xué)習(xí)~~~
書山有路勤為徑,學(xué)海無涯苦作舟!

掃碼二維碼
獲取更多精彩
Java樂園

