設(shè)計(jì)模式系列-模板方法模式

JAVA設(shè)計(jì)模式系列:

模板方法模式

定義

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

實(shí)現(xiàn)

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


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

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

CaffeineBeverage類(lèi)中定義了一個(gè)名為prepareReipe()的模板方法,用來(lái)描述沖泡咖啡因飲料的過(guò)程。方法用final修飾是為了防止子類(lèi)修改方法的執(zhí)行順序。
CaffeineBeverage類(lèi)定義了4個(gè)方法,分別是brew()addCondiments()、boilWater()pourInCup()。在我們的示例中,沖泡咖啡和茶共有的過(guò)程分別是煮水 boilWater()、倒進(jìn)杯子里 pourInCup()。這兩個(gè)共用方法選擇在CaffeineBeverage類(lèi)實(shí)現(xiàn)。
Tea類(lèi)、Coffee類(lèi)是CaffeineBeverage類(lèi)的子類(lèi)。而加料 addCondiments()、浸泡 brew()分別在Tea類(lèi)、Coffee類(lèi)中有各自不同的實(shí)現(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");
}
}

完成了模板方法模式的代碼,我們可以進(jìn)行測(cè)試一下,測(cè)試類(lèi):

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

輸出結(jié)果:

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

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

鉤子

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

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

并修改模板方法:

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

目的是增加讓客戶(hù)選擇是否需要給茶或者飲料來(lái)添加?xùn)|西。我們可以在子類(lèi)中覆蓋鉤子的寫(xiě)法。這里改下下Tea類(lèi),如下:

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;
}
}
}

添加了一個(gè)msg變量,可以通過(guò)構(gòu)造函數(shù)進(jìn)行賦值,當(dāng)msgy時(shí)候,我們將在茶里添加檸檬,否則不添加??匆幌聹y(cè)試代碼:

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

運(yùn)行結(jié)果:

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

和上面的比較一下,發(fā)現(xiàn)制作茶的過(guò)程中缺少了添加?xùn)|西的過(guò)程,主要是因?yàn)槲覀冊(cè)?code>Tea類(lèi),重寫(xiě)了鉤子,來(lái)控制加料的步驟。

如有紕漏,煩請(qǐng)指出。

代碼地址:GitHub

參考《Head First 設(shè)計(jì)模式》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容