一、概念 模板方法模式:在一個方法中定義一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟。 解析:模板方法模式用來創建一個演算法的模板。什麼是模板?模板就是一個方法。更具體地說,這個方法將演算法定義成一組步驟,其中的任何步驟都可以是抽象的, ...
一、概念
- 模板方法模式:在一個方法中定義一個演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法中的某些步驟。
- 解析:模板方法模式用來創建一個演算法的模板。什麼是模板?模板就是一個方法。更具體地說,這個方法將演算法定義成一組步驟,其中的任何步驟都可以是抽象的,由子類負責實現。這可以確保演算法的結構保持不變,同時由子類提供部分實現。
- 角色:
1、抽象模板(Abstract Template):定義模板方法,規範了一組步驟,其中父類可以實現其中的某些步驟,需要由子類實現的步驟聲明為 abstract。
2、具體模板(Concrete Template):繼承抽象父類,實現抽象父類中聲明為 abstract 的方法。
二、Demo 實現
我們打算定義一個咖啡因飲料沖泡流程,把流程中相同的步驟放在一起,同時,不同的飲料還能有自己的具體實現。
1、抽象模板
public abstract class CaffeineBeverage {
/**
* @Description
* 1、模板方法,定義演算法的步驟。
* 2、我們一般把模板方法定義成 final,不希望子類覆蓋。
*/
public final void prepareRecipe() {
//1、把水煮沸
boilWater();
//2、用熱水泡飲料(具體什麼飲料未知)
brew();
//3、把飲料倒進杯子
pourIncup();
//4、往飲料中添加調料(具體什麼調料未知)
if (wantAddCondiments()) {
addCondiments();
}
}
/**
* @Description 需要子類提供實現的步驟定義為抽象
*/
protected abstract void brew();
protected abstract void addCondiments();
/**
* @Description 由父類提供實現,又不希望被子類重寫的,封裝成 private。
*/
private void boilWater() {
System.out.println("Boiling water");
}
private void pourIncup() {
System.out.println("Pouring into cup");
}
/**
* @Description 鉤子方法
* 1、鉤子是一種被聲明在抽象類中的方法,當只有空的或者預設的實現。
* 2、鉤子的存在,可以讓子類有能力對演算法的不同點進行掛鉤(重寫)。
* 3、要不要掛鉤(重寫),由子類自己決定。
*/
protected boolean wantAddCondiments() {
return true;
}
}
這裡,我們定義了一個抽象模板,規範了具體的沖泡流程 —— 把水煮沸->泡飲料->倒杯子->添加調料。在抽象模板中,我們有三種類型的方法,一種需要子類提供實現的,我們定義為 abstract ;一種父類提供實現,又不希望被子類覆蓋的,我們定義為 private;還有一種稱為鉤子方法,父類提供預設實現,子類可自由選擇是否重寫父類的方法。
2、具體模板
public class Coffee extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("Dripping Coffee through filter");
}
@Override
protected void addCondiments() {
System.out.println("Adding Suger and Milk");
}
}
public class Tea extends CaffeineBeverage {
@Override
protected void brew() {
System.out.println("Steeping the tea");
}
@Override
protected void addCondiments() {
System.out.println("Adding Lemon");
}
/**
* @Description 子類重寫鉤子方法
*/
@Override
protected boolean wantAddCondiments() {
return false;
}
}
具體模板繼承了抽象模板,實現了抽象模板中定義為 abstract 的步驟方法,並可以自己選擇是否重寫鉤子方法。
3、測試
public class Test {
public static void main(String[] args) {
CaffeineBeverage coffee = new Coffee();
CaffeineBeverage tea = new Tea();
coffee.prepareRecipe();
tea.prepareRecipe();
}
}
三、總結
- 模板方法模式的通用類圖非常簡單,僅僅使用了Java的繼承機制,但它是一個非常廣泛的模式。
- 優點:
1、封裝不變部分,擴展可變部分。把認為不變部分的演算法封裝到父類中實現,而可變部分的則可以通過繼承來繼續擴展。可以將代碼最大復用化。
2、父類規範演算法行為,子類提供完整實現。
- 使用場景:
1、多個子類有共有的方法,並且邏輯基本相同。
2、一次性實現一個演算法的不變部分,並且將可變的行為留給子類來完成。
- 為防止子類改變模板方法中的演算法,可以將模板方法聲明為 final。
- 策略模式和模板方法模式都封裝演算法,但是策略模式使用的是組合,模板方法模式使用的是繼承。
- 工廠方法是模板方法的一種特殊版本。
- 低層組件可以調用高層組件中的方法(實際上子類會常常調用其從父類中繼承所來的方法),但是我們要做的是要避免讓高層和底層組件之間有明顯的環狀依賴。