Java設(shè)計(jì)模式之模板方法模式
在我們實(shí)際開發(fā)中,如果一個(gè)方法極其復(fù)雜時(shí),如果我們將所有的邏輯寫在一個(gè)方法中,那維護(hù)起來就很困難,要替換某些步驟時(shí)都要重新寫,這樣代碼的擴(kuò)展性就很差,當(dāng)遇到這種情況就要考慮今天的主角——模板方法模式。
一、概念理解
模板方法模式的概念很簡單,在一個(gè)方法中定義一個(gè)算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。
既然概念叫“骨架”,那想當(dāng)然的就是定義一個(gè)抽象類,這是模板方法模式的第一個(gè)角色——抽象模板角色,要有延遲子類實(shí)現(xiàn)骨架方法,這是模板方法的第二個(gè)角色——具體模板角色。
抽象模板角色:定義了一個(gè)或多個(gè)抽象操作,以便讓子類實(shí)現(xiàn)。這些抽象操作叫做基本操作,它們是一個(gè)頂級邏輯的組成步驟,定義并實(shí)現(xiàn)了一個(gè)模板方法。
具體模板角色:實(shí)現(xiàn)父類所定義的一個(gè)或多個(gè)抽象方法,它們是一個(gè)頂級邏輯的組成步驟。每一個(gè)抽象模板角色都可以有任意多個(gè)具體模板角色與之對應(yīng)。
二、案例實(shí)現(xiàn)
在我們的業(yè)務(wù)開發(fā)中往往都需要很多對象、很多方法,對象間也大都存在依賴關(guān)系,如果我們手動創(chuàng)建、管理對象就是一件極其困難的事。
如果我們使用工廠模式用于創(chuàng)建對象,使用一個(gè)容器用于管理對象,那么再使用起來就變得極其簡單了。
在“這個(gè)過程”中創(chuàng)建對象就是一個(gè)很復(fù)雜的算法,而且創(chuàng)建對象的方式往往也不是單一的,我們要考慮能替換算法,這時(shí)候就可以使用模板方法模式。
假設(shè)創(chuàng)建對象有兩種方式,一種是基于注解,一種是基于xml,我們就將該方法定義為一個(gè)模板方法,基于注解和基于xml讓子類去實(shí)現(xiàn)。
我們用refresh()方法代表這個(gè)復(fù)雜的過程,在這個(gè)過程中應(yīng)該包括:
①開始工作前的預(yù)處理;
②創(chuàng)建管理對象的容器(模板方法,基于注解和基于XML交給子類實(shí)現(xiàn));
③模板方法(交給子類,方便擴(kuò)展);
④其他方法(容器刷新后、國際化、應(yīng)用監(jiān)聽、發(fā)布事件,等等等一堆事)。
我們基于模板方法模式我們實(shí)現(xiàn)簡單的demo。
抽象模板角色:
我們在抽象模板角色中實(shí)現(xiàn)部分邏輯,而創(chuàng)建對象的容器obtainFreshBeanFactory()方法交給子類實(shí)現(xiàn),onRefresh()空方法交給子類實(shí)現(xiàn)便于擴(kuò)展。
/**
* 抽象模板角色
* @author tcy
* @Date 28-09-2022
*/
public abstract class AbstractApplicationContext {
/**
* 案例中容器和對象的創(chuàng)建全過程
*/
public void refresh(){
this.prepareRefresh();
this.obtainFreshBeanFactory();
this.onRefresh();
}
protected void prepareRefresh(){
System.out.println("我用于開始工作前的預(yù)處理...");
}
protected void obtainFreshBeanFactory(){
System.out.println("我用于創(chuàng)建默認(rèn)管理對象的容器...");
}
/**
* 模板方法,子類去實(shí)現(xiàn)[springboot實(shí)現(xiàn)了他,感興趣具體可以研究一下]
*/
protected void onRefresh() {
}
protected void otherMethod(){
System.out.println("容器刷新后、國際化、應(yīng)用監(jiān)聽、發(fā)布事件,等等等,一堆事");
}
}具體模板角色-基于注解創(chuàng)建管理對象的容器
/**
* 具體模板角色-基于注解
* @author tcy
* @Date 28-09-2022
*/
public class ApplicationContextAnnotation extends AbstractApplicationContext {
@Override
protected void obtainFreshBeanFactory() {
System.out.println("這是基于注解的創(chuàng)建對象容器...");
}
}具體模板角色-基于xml創(chuàng)建管理對象的容器
/**
* 具體模板角色-基于xml
* @author tcy
* @Date 28-09-2022
*/
public class ApplicationContextXml extends AbstractApplicationContext {
@Override
protected void obtainFreshBeanFactory() {
System.out.println("這是xml的創(chuàng)建對象容器...");
}
}客戶端-模擬容器啟動過程:
/**
* 容器啟動過程
* @author tcy
* @Date 28-09-2022
*/
public class Client {
public static void main(String[] args) {
//基于xml方式
ApplicationContextXml applicationContextXml = new ApplicationContextXml();
applicationContextXml.refresh();
//基于注解方式
ApplicationContextAnnotation annotation=new ApplicationContextAnnotation();
annotation.refresh();
}
}我用于開始工作前的預(yù)處理...
這是xml的創(chuàng)建對象容器...
容器刷新后、國際化、應(yīng)用監(jiān)聽、發(fā)布事件,等等等,一堆事
我用于開始工作前的預(yù)處理...
這是基于注解的創(chuàng)建對象容器...
容器刷新后、國際化、應(yīng)用監(jiān)聽、發(fā)布事件,等等等,一堆事
對Spring源碼稍微有點(diǎn)了解的同學(xué)大概已經(jīng)知道,我們案例實(shí)現(xiàn)的正是簡易版的Spring的Refresh()方法,Refresh()方法是Spring最核心的方法,Spring良好的擴(kuò)展性正是離不開模板方法模式的運(yùn)用。下圖為Spring核心Refresh()方法的執(zhí)行大流程注釋。
在我們案例中的onRefresh()的空方法,實(shí)際中Springboot就是實(shí)現(xiàn)了這個(gè)空方法,onRefresh()方法調(diào)用了Tomcat的jar包啟動,這也是Springboot不需要手動注入Tomcat的原因。
相信通過這個(gè)案例的理解,大部分同學(xué)不僅能很好的理解模板方法模式,想必對Spring的啟動過程也有了一個(gè)大概的了解。
三、總結(jié)
模板方法應(yīng)用場景太普遍了,在實(shí)際開發(fā)中有多個(gè)子類共有的方法,并且邏輯相同,可以考慮使用模板方法模式。當(dāng)面對重要、復(fù)雜的算法,也可以把核心算法設(shè)計(jì)為模板方法模式,相關(guān)細(xì)節(jié)則由各個(gè)子類實(shí)現(xiàn)。
模板方法優(yōu)點(diǎn)突出:封裝不變部分,擴(kuò)展可變部分;提取公共代碼,便于維護(hù);行為由父類控制,子類實(shí)現(xiàn)。
模板方法的缺點(diǎn)很明顯,當(dāng)方法實(shí)現(xiàn)過多的時(shí)候,每一個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類來實(shí)現(xiàn),這必然導(dǎo)致類的個(gè)數(shù)增加,使得系統(tǒng)變得更加龐大。
到此這篇關(guān)于Java設(shè)計(jì)模式之模板方法模式的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java使用BigDecimal公式精確計(jì)算及精度丟失問題
在工作中經(jīng)常會遇到數(shù)值精度問題,比如說使用float或者double的時(shí)候,可能會有精度丟失問題,下面這篇文章主要給大家介紹了關(guān)于Java使用BigDecimal公式精確計(jì)算及精度丟失問題的相關(guān)資料,需要的朋友可以參考下2023-01-01
SpringBoot 開發(fā)提速神器 Lombok+MybatisPlus+SwaggerUI
這篇文章主要介紹了SpringBoot 開發(fā)提速神器 Lombok+MybatisPlus+SwaggerUI,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
一個(gè)依賴搞定?Spring?Boot?接口防盜刷的流程分析
kk-anti-reptile 是適用于基于 spring-boot 開發(fā)的分布式系統(tǒng)的反爬蟲組件,這篇文章主要介紹了一個(gè)依賴搞定?Spring?Boot?接口防盜刷,需要的朋友可以參考下2022-06-06
通過實(shí)例解析java8中的parallelStream
這篇文章主要介紹了通過實(shí)例解析java8中的parallelStream,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Spring運(yùn)行時(shí)動態(tài)注冊bean的方法
這篇文章主要介紹了Spring運(yùn)行時(shí)動態(tài)注冊bean的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
使用StringRedisTemplate操作Redis方法詳解
這篇文章主要為大家介紹了使用StringRedisTemplate操作Redis方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08


