設計模式系列-模板方法模式

JAVA設計模式系列:

模板方法模式

定義

模板方法模式在一個方法中定義了算法的骨架,把其中的某些步驟延遲到子類的實現(xiàn),是為我們提供了代碼復用的一種重要的技巧。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。

實現(xiàn)

這里簡單通過一個示例來展示到底什么時候模板方法模式。這個示例向我們展示了制作咖啡和茶2種咖啡因飲料的過程,在這個過程中展示了模板方法模式的具體使用方法。
代碼地址:GitHub
先看一下模板方法模式的類圖:


首先我們定義一個抽象類CaffeineBeverage來作為模板方法的基類。具體代碼如下:

public abstract class CaffeineBeverage {
// 模板方法
final void prepareReipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 浸泡
abstract void brew();
// 加料
abstract void addCondiments();
// 煮水
void boilWater() {
System.out.println("Boiling water");
}
// 倒進杯子里
void pourInCup() {
System.out.println("Pouring into cup");
}

CaffeineBeverage類中定義了一個名為prepareReipe()的模板方法,用來描述沖泡咖啡因飲料的過程。方法用final修飾是為了防止子類修改方法的執(zhí)行順序。
CaffeineBeverage類定義了4個方法,分別是brew()addCondiments()boilWater()pourInCup()。在我們的示例中,沖泡咖啡和茶共有的過程分別是煮水 boilWater()倒進杯子里 pourInCup()。這兩個共用方法選擇在CaffeineBeverage類實現(xiàn)。
Tea類、Coffee類是CaffeineBeverage類的子類。而加料 addCondiments()浸泡 brew()分別在Tea類、Coffee類中有各自不同的實現(xiàn)。如下所示:

public class Tea extends CaffeineBeverage {
void brew() {
System.out.println("Stepping the tea.");
}
void addCondiments() {
System.out.println("Adding Lemon");
}
}
public class Coffee extends CaffeineBeverage {
void brew() {
System.out.println("Dripping Coffee through filter");
}
void addCondiments() {
System.out.println("Adding Suger and Mike");
}
}

完成了模板方法模式的代碼,我們可以進行測試一下,測試類:

public class Test {
public static void main(String[] args) {
Tea tea = new Tea();
tea.prepareReipe();
System.out.println("**************");
Coffee coffee = new Coffee();
coffee.prepareReipe();
}
}

輸出結果:

Boiling water
Stepping the tea.
Pouring into cup
Adding Lemon
**************
Boiling water
Dripping Coffee through filter
Pouring into cup
Adding Suger and Mike

我們將沖茶和咖啡重復的方法煮水 boilWater()倒進杯子里 pourInCup()抽象出來,每個子類分別去實現(xiàn)各自特有的步驟。以上便是模板方法的實例。

鉤子

還需了解到,模板方法模式還有鉤子的概念。鉤子是一種被聲明在抽象類的方法,可以為空或者默認的實現(xiàn)。鉤子的存在可以讓子類有能力對算法的不同點進行掛鉤,是否需要掛鉤由子類決定。
借助上面的示例來展示鉤子如何使用。首先我們在抽象類CaffeineBeverage定一個鉤子,鉤子的默認實現(xiàn)返回true。如下:

// 定義一個鉤子
boolean customerWantsCondiments() {
return true;
}

并修改模板方法:

// 模板方法
final void prepareReipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}

目的是增加讓客戶選擇是否需要給茶或者飲料來添加東西。我們可以在子類中覆蓋鉤子的寫法。這里改下下Tea類,如下:

public class Tea extends CaffeineBeverage {
private String msg;
public Tea(String msg) {
this.msg = msg;
}
void brew() {
System.out.println("Stepping the tea.");
}
void addCondiments() {
System.out.println("Adding Lemon");
}
boolean customerWantsCondiments() {
if ("y".equals(this.msg)) {
return true;
} else {
return false;
}
}
}

添加了一個msg變量,可以通過構造函數(shù)進行賦值,當msgy時候,我們將在茶里添加檸檬,否則不添加。看一下測試代碼:

public static void main(String[] args) {
Tea tea = new Tea("n");
tea.prepareReipe();
System.out.println("**************");
Coffee coffee = new Coffee();
coffee.prepareReipe();
}

運行結果:

Boiling water
Stepping the tea.
Pouring into cup
**************
Boiling water
Dripping Coffee through filter
Pouring into cup
Adding Suger and Mike

和上面的比較一下,發(fā)現(xiàn)制作茶的過程中缺少了添加東西的過程,主要是因為我們在Tea類,重寫了鉤子,來控制加料的步驟。

如有紕漏,煩請指出。

代碼地址:GitHub

參考《Head First 設計模式》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容