簡介
Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
模板方法模式(Template Method Pattern) 實際上是封裝了一個固定流程,該流程由幾個步驟組成,具體步驟可以由子類進行不同實現(xiàn),從而讓固定的流程產(chǎn)生不同的結(jié)果。
模板方法模式 非常簡單,其實就是類的繼承機制,但它卻是一個應(yīng)用非常廣泛的模式。
模板方法模式 本質(zhì):抽象封裝流程,具體進行實現(xiàn)
主要解決
當(dāng)完成一個操作具有固定的流程時,由抽象固定流程步驟,具體步驟交給子類進行具體實現(xiàn)(固定的流程,不同的實現(xiàn))。
優(yōu)缺點
優(yōu)點
- 封裝不變,擴展可變:父類封裝了具體流程以及實現(xiàn)部分不變行為,其它可變行為交由子類進行具體實現(xiàn);
- 流程由父類控制,子類進行實現(xiàn):框架流程由父類限定,子類無法更改;子類可以針對流程某些步驟進行具體實現(xiàn);
缺點
- 抽象規(guī)定了行為,具體負責(zé)實現(xiàn),與通常事物的行為相反,會帶來理解上的困難(通俗地說,“父類調(diào)用了子類方法”);
使用場景
- 多個子類有公有的方法,并且邏輯基本相同時;
- 重要,復(fù)雜的算法,可以把核心算法設(shè)計為模板方法,周邊的相關(guān)細節(jié)功能則由各個子類實現(xiàn);
- 重構(gòu)時,模板方法模式 是一個經(jīng)常使用的模式,把相同的代碼抽取到父類,然后通過鉤子函數(shù)約束其行為;
模式講解
首先來看下 模板方法模式 的通用 UML 類圖:

從 UML 類圖中,我們可以看到,模板方法模式 主要包含兩種角色:
- 抽象模板(AbstractClass):抽象模板類,定義了一套算法框架/流程;
- 具體實現(xiàn)(ConcreteClass):具體實現(xiàn)類,對算法框架/流程的某些步驟進行了實現(xiàn);
以下是 模板方法模式 的通用代碼:
class Client {
public static void main(String[] args) {
AbstractClass abc = new ConcreteClassA();
abc.templateMehthod();
abc = new ConcreteClassB();
abc.templateMehthod();
}
// 抽象模板類
static abstract class AbstractClass {
protected void step1() {
System.out.println("AbstractClass:step1");
}
protected void step2() {
System.out.println("AbstractClass:step2");
}
protected void step3() {
System.out.println("AbstractClass:step3");
}
// 聲明為final方法,避免子類覆寫
public final void templateMehthod() {
this.step1();
this.step2();
this.step3();
}
}
// 具體實現(xiàn)類A
static class ConcreteClassA extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreateClassA:step1");
}
}
// 具體實現(xiàn)類B
static class ConcreteClassB extends AbstractClass {
@Override
protected void step2() {
System.out.println("ConcreateClassB:step2");
}
}
}
注:通常把抽象模板類AbstractClass的模板方法templateMethod定義成final類型,避免子類對其覆寫,并遵命定義算法結(jié)構(gòu)/流程的語義。
舉個例子
例子:小明要炒兩道菜:炒豆芽和炒茄子;
分析:炒菜都有固定步驟:洗菜,熱鍋下油,下菜翻炒,下調(diào)料,起鍋。由于炒菜流程是固定的,而其中有些步驟對不同的菜而言具備不同的操作,因此可以很好地使用 模板方法模式 完成炒菜過程。
具體代碼如下:
class Client {
public static void main(String[] args) {
System.out.println("準(zhǔn)備炒豆芽");
CookVegetable cookVegetable = new CookBeanSprout();
cookVegetable.cook();
System.out.println();
System.out.println("準(zhǔn)備炒茄子");
cookVegetable = new CookEggplant();
cookVegetable.cook();
}
// 抽象模板類:定義炒菜流程
static abstract class CookVegetable {
protected void wash() {
System.out.println("洗菜");
}
protected void pourOil() {
System.out.println("熱油下鍋");
}
protected void fry() {
System.out.println("下菜翻炒");
}
// 具體調(diào)料由菜決定
protected abstract void pourSauce();
// 具體炒菜流程
public final void cook() {
this.wash();
this.pourOil();
this.fry();
this.pourSauce();
System.out.println("起鍋吃菜");
}
}
// 豆芽
static class CookBeanSprout extends CookVegetable {
@Override
protected void pourOil() {
System.out.println("熱鍋少油");
}
@Override
protected void fry() {
System.out.println("快速翻炒");
}
@Override
protected void pourSauce() {
System.out.println("加鹽和少量生抽");
}
}
// 茄子
static class CookEggplant extends CookVegetable {
@Override
protected void wash() {
System.out.println("去除頭尾,然后用水洗下");
}
@Override
protected void pourOil() {
System.out.println("熱鍋多油");
}
@Override
protected void pourSauce() {
System.out.println("加鹽和雞精");
}
}
}
結(jié)果如下:
準(zhǔn)備炒豆芽
洗菜
熱鍋少油
快速翻炒
加鹽和少量生抽
起鍋吃菜
準(zhǔn)備炒茄子
去除頭尾,然后用水洗下
熱鍋多油
下菜翻炒
加鹽和雞精
我們根據(jù) 模板方法模式,就可以抽象定義炒菜的流程,然后針對不同的菜品,由其子類對某些炒菜步驟進行具體實現(xiàn),這樣就完成了炒菜過程。