個人學習筆記分享,當前能力有限,請勿貶低,菜鳥互學,大佬繞道
如有勘誤,歡迎指出和討論,本文后期也會進行修正和補充
開發(fā)過程中,我們通常會遇到這樣的情況:我們已經制定好了方案,并確定了相關執(zhí)行步驟,但某些具體的步驟還未知,或者說具體的步驟與環(huán)境相關
如,乘坐飛機、火車等交通工具出遠門,都需要買票-驗票進站-等車-上車-下車-出站等一套流程,但具體需要處理的細節(jié)卻不完全一樣,買票的渠道、驗票進站的步驟、上下飛機/火車的方式等等,都不一樣。
那么,我們可以把這些規(guī)定了流程或格式的實例定義成模板,允許使用者根據(jù)自己的需求去更新它
1.定義
使用目的:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟
使用時機:有一套相同的流程,但具體實現(xiàn)方案不一樣
解決問題:流程中的一些方法通用,卻在每一個子類都重新寫了這一方法。
實現(xiàn)方法:流程在抽象類實現(xiàn),步驟在子類實現(xiàn)。
應用實例:
- 乘坐飛機、火車、輪船等交通工具的流程,都需要買票-驗票-候車-上車-下車-出站的流程
- spring對事務的處理,如開啟事務、獲取 Session、關閉 Session 等
- MVC模型
優(yōu)點:
- 封裝不變部分,擴展可變部分。
- 提取公共代碼,便于維護。
- 行為由父類控制,子類實現(xiàn)
缺點:
- 對每個不同的實現(xiàn)都需要定義一個子類,這會導致類的個數(shù)增加,系統(tǒng)更加龐大,設計也更加抽象,間接地增加了系統(tǒng)實現(xiàn)的復雜度。
- 父類中的抽象方法由子類實現(xiàn),子類執(zhí)行的結果會影響父類的結果,這導致一種反向的控制結構,它提高了代碼閱讀的難度。
- 由于繼承關系自身的缺點,如果父類添加新的抽象方法,則所有子類都要改一遍。
注意事項:為防止惡意操作,一般模板方法都加上 final 關鍵詞。
2.結構
模板模式包含以下角色:
- 抽象類/抽象模板(Abstract Class):負責給出一個算法的輪廓和骨架。它由一個模板方法和若干個基本方法構成
- 具體子類/具體實現(xiàn)(Concrete Class):實現(xiàn)抽象類中所定義的抽象方法和鉤子方法,它們是一個頂級邏輯的一個組成步驟

3.步驟
-
構建抽象模板類
//抽象類 abstract class AbstractClass { //模板方法 public void TemplateMethod() { SpecificMethod(); abstractMethod1(); abstractMethod2(); abstractMethod3(); } //具體方法 public void SpecificMethod() { System.out.println("抽象類中的具體方法被調用..."); } //抽象方法1 public abstract void abstractMethod1(); //抽象方法2 public abstract void abstractMethod2(); //抽象方法2 public abstract void abstractMethod3(); } -
構建具體子類
//具體子類A class ConcreteClassA extends AbstractClass { public void abstractMethod1() { System.out.println("模板A中的方法1被調用"); } public void abstractMethod2() { System.out.println("模板A中的方法2被調用..."); } @Override public void abstractMethod3() { System.out.println("模板A中的方法3被調用..."); } } //具體子類B class ConcreteClassB extends AbstractClass { public void abstractMethod1() { System.out.println("模板B中的方法1被調用"); } public void abstractMethod2() { System.out.println("模板B中的方法2被調用..."); } @Override public void abstractMethod3() { System.out.println("模板B中的方法3被調用..."); } }
測試代碼
public class TemplateTest {
public static void main(String[] args) {
AbstractClass tmA = new ConcreteClassA();
tmA.TemplateMethod();
AbstractClass tmB = new ConcreteClassB();
tmB.TemplateMethod();
}
}
運行結果

4.擴展
模板模式由抽象模板規(guī)定了算法的骨架,即具體方法的執(zhí)行順序和邏輯
那么,我們可以通過鉤子方法,使不同的具體子類能夠執(zhí)行不同的具體方法
具體代碼
package com.company.designPattern.template;
public class TemplateHockTest {
public static void main(String[] args) {
AbstractHockClass tmA = new ConcreteHockClassA();
tmA.TemplateMethod();
}
}
//抽象類
abstract class AbstractHockClass {
//模板方法
public void TemplateMethod() {
SpecificMethod();
// 執(zhí)行鉤子1和具體方法1
hockMethod1();
abstractMethod1();
// 根據(jù)鉤子2結果是否執(zhí)行具體方法2
if (hockMethod2()) {
abstractMethod2();
}
}
//具體方法
public void SpecificMethod() {
System.out.println("抽象類中的具體方法被調用...");
}
// 鉤子方法1
public void hockMethod1() {
System.out.println("默認鉤子方法1被調用");
}
//抽象方法1
public abstract void abstractMethod1();
// 鉤子方法2
public boolean hockMethod2() {
System.out.println("默認鉤子方法2被調用");
return true;
}
//抽象方法2
public abstract void abstractMethod2();
}
//具體子類A
class ConcreteHockClassA extends AbstractHockClass {
public void abstractMethod1() {
System.out.println("模板A中的方法1被調用");
}
public void abstractMethod2() {
System.out.println("模板A中的方法2被調用...");
}
@Override
public boolean hockMethod2() {
System.out.println("默認鉤子方法2被調用");
return false;
}
}
通過鉤子方法,我們達到下面效果
- 執(zhí)行通用具體方法
- 通過鉤子1對方法1進行預處理
- 根據(jù)鉤子2判斷是否執(zhí)行方法2
執(zhí)行結果

后記
模板方法的目的是將按照統(tǒng)一模板的方法進一步規(guī)范化,通過繼承重寫和模板方法來保證多個具體子類按照同樣的算法執(zhí)行
說白點,量產化,將統(tǒng)一的方法通過父類的abstract方法控制,統(tǒng)一的流程通過父類中的模板方法設定,子類自行控制每個步驟的執(zhí)行細節(jié)
當然也可以根據(jù)實際需求進行變型,畢竟服務于實際開發(fā)才是設計模式的目的
作者:Echo_Ye
WX:Echo_YeZ
Email :echo_yezi@qq.com
個人站點:在搭了在搭了。。。(右鍵 - 新建文件夾)