定義
模板方法模式是所有模式中最為常見的幾個模式之一,是基於繼承的代碼復用的基本技術。,沒有關聯關系。
因此,在模板方法模式的類結構圖中,只有繼承關系。
模板方法模式需要開發抽象類和具體子類的設計師之間的協作。一個設計師負責給出一個算法的輪廓和骨架,另一些設計師則負責給出這個算法的各個邏輯步驟。
結構
AbstractClass : 抽象類,定義並實現一個模板方法。這個模板方法定義了算法的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類去實現。頂級邏輯也有可能調用一些具體方法。
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
public void TemplateMethod() {
PrimitiveOperation1();
PrimitiveOperation2();
}
}
@Override
public void PrimitiveOperation1() {
System.out.println("具體A類方法1");
}
@Override
public void PrimitiveOperation2() {
System.out.println("具體A類方法2");
}
}
class ConcreteClassB extends AbstractClass {
@Override
public void PrimitiveOperation1() {
System.out.println("具體B類方法1");
}
@Override
public void PrimitiveOperation2() {
System.out.println("具體B類方法2");
}
}
public static void main(String[] args) {
AbstractClass objA = new ConcreteClassA();
AbstractClass objB = new ConcreteClassB();
objA.TemplateMethod();
objB.TemplateMethod();
}
}
要點
2、抽象方法(Abstract Method)
3、鈎子方法(Hook Method)
三類角色的關聯
在模板方法模式中,首先父類會定義一個算法的框架,即實現算法所必須的所有方法。
其中,具有共性的代碼放在父類的具體方法中。
各個子類特殊性的代碼放在子類的具體方法中。但是父類中需要有對應抽象方法聲明。
鈎子方法可以讓子類決定是否對算法的不同點進行掛鈎。
總結
使用模板方法模式可以將代碼的公共行為提取,以達到復用的目的。
而對於特殊化的行為在子類中實現。父類的模板方法可以控制子類中的具體實現。
子類無需了解整體算法框架,只需實現自己的業務邏輯即可。
實例
模板方法模式應用場景十分廣泛。
現實生活中,茶和咖啡是隨處可見的飲料。沖泡一杯茶或沖泡一杯咖啡的過程是怎樣的?
我們來整理一下流程。
泡茶:
燒開水 ==> 沖泡茶葉 ==> 倒入杯中 ==> 添加檸檬 泡咖啡: 燒開水 ==> 沖泡咖啡 ==> 倒入杯中 ==> 添加糖和牛奶 |
由以上處理步驟不難發現,准備這兩種飲料的處理過程非常相似。我們可以使用模板類方法去限定制作飲料的算法框架。
其中相同的具有共性的步驟(如燒開水、倒入杯中),直接在抽象類中給出具體實現。
而對於有差異性的步驟,則在各自的具體類中給出實現。
// 模板方法,決定了算法骨架。相當於TemplateMethod()方法
public void prepareBeverage() {
boilWater();
brew();
pourInCup();
if (customWantsCondiments())
{
addCondiments();
}
}
// 共性操作,直接在抽象類中定義
public void boilWater() {
System.out.println("燒開水");
}
// 共性操作,直接在抽象類中定義
public void pourInCup() {
System.out.println("倒入杯中");
}
// 鈎子方法,決定某些算法步驟是否掛鈎在算法中
public boolean customWantsCondiments() {
return true;
}
// 特殊操作,在子類中具體實現
public abstract void brew();
// 特殊操作,在子類中具體實現
public abstract void addCondiments();
}
@Override
public void brew() {
System.out.println("沖泡茶葉");
}
@Override
public void addCondiments() {
System.out.println("添加檸檬");
}
}
class Coffee extends Beverage {
@Override
public void brew() {
System.out.println("沖泡咖啡豆");
}
@Override
public void addCondiments() {
System.out.println("添加糖和牛奶");
}
}
System.out.println("============= 准備茶 =============");
Beverage tea = new Tea();
tea.prepareBeverage();
System.out.println("============= 准備咖啡 =============");
Beverage coffee = new Coffee();
coffee.prepareBeverage();
}
燒開水
沖泡茶葉
倒入杯中
添加檸檬
============= 准備咖啡 =============
燒開水
沖泡咖啡豆
倒入杯中
添加糖和牛奶