1.定義
定義一個(gè)操作中的算法骨架,而將算法的一些步驟延遲到子類(lèi)中,使得子類(lèi)可以不改變?cè)撍惴ńY(jié)構(gòu)的情況下重定義該算法的某些特定步驟。
2.結(jié)構(gòu)
模板方法(Template Method)模式包含以下主要角色:
-
抽象類(lèi)(Abstract Class):負(fù)責(zé)給出一個(gè)算法的輪廓和骨架。它由一個(gè)模板方法和若干個(gè)基本方法構(gòu)成。
-
模板方法:定義了算法的骨架,按某種順序調(diào)用其包含的基本方法。
-
基本方法:是實(shí)現(xiàn)算法各個(gè)步驟的方法,是模板方法的組成部分?;痉椒ㄓ挚梢苑譃槿N:
-
抽象方法(Abstract Method) :一個(gè)抽象方法由抽象類(lèi)聲明、由其具體子類(lèi)實(shí)現(xiàn)。
-
具體方法(Concrete Method) :一個(gè)具體方法由一個(gè)抽象類(lèi)或具體類(lèi)聲明并實(shí)現(xiàn),其子類(lèi)可以進(jìn)行覆蓋也可以直接繼承。
-
鉤子方法(Hook Method) :在抽象類(lèi)中已經(jīng)實(shí)現(xiàn),包括用于判斷的邏輯方法和需要子類(lèi)重寫(xiě)的空方法兩種。
一般鉤子方法是用于判斷的邏輯方法,這類(lèi)方法名一般為isXxx,返回值類(lèi)型為boolean類(lèi)型。
-
-
-
具體子類(lèi)(Concrete Class):實(shí)現(xiàn)抽象類(lèi)中所定義的抽象方法和鉤子方法,它們是一個(gè)頂級(jí)邏輯的組成步驟。
3.案例實(shí)現(xiàn)
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/21 16:47
* 抽象類(lèi)(定義模板方法和基本方法)
*/
public abstract class AbstractClass {
// 模板方法 加上final不讓子類(lèi)改變方法結(jié)構(gòu)
public final void cookProcess() {
// 第一步,倒油
this.pourOil();
// 第二步,熱油
this.heatOil();
// 第三步,倒蔬菜
this.pourVegetable();
// 第四步,倒調(diào)味料
this.pourSauce();
// 第五步,翻炒
this.fry();
}
// 抽象方法
public abstract void pourSauce();
public abstract void pourVegetable();
// 具體方法
private void fry() {
System.out.println("翻炒");
}
private void heatOil() {
System.out.println("熱油");
}
private void pourOil() {
System.out.println("倒油");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/25 0:46
* 炒包菜類(lèi) 具體的類(lèi)
*/
public class ConcreteClass_BaoCai extends AbstractClass {
@Override
public void pourSauce() {
System.out.println("下鍋的醬料是辣椒");
}
@Override
public void pourVegetable() {
System.out.println("下鍋的蔬菜是包菜");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/25 0:46
* 炒菜芯類(lèi) 具體的類(lèi)
*/
public class ConcreteClass_CaiXin extends AbstractClass {
@Override
public void pourSauce() {
System.out.println("下鍋的醬料是蒜蓉");
}
@Override
public void pourVegetable() {
System.out.println("下鍋的蔬菜是菜芯");
}
}
/**
* @author 曉風(fēng)殘?jiān)翷x
* @date 2023/7/25 0:48
*/
public class Client {
public static void main(String[] args) {
// 炒包菜
// 創(chuàng)建對(duì)象
ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
baoCai.cookProcess();
// 炒菜芯
ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();
caiXin.cookProcess();
}
}
4.優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
-
提高代碼復(fù)用性
將相同部分的代碼放在抽象的父類(lèi)中,而將不同的代碼放入不同的子類(lèi)中。
-
實(shí)現(xiàn)了反向控制
通過(guò)一個(gè)父類(lèi)調(diào)用其子類(lèi)的操作,通過(guò)對(duì)子類(lèi)的具體實(shí)現(xiàn)擴(kuò)展不同的行為,實(shí)現(xiàn)了反向控制 ,并符合“開(kāi)閉原則”。
缺點(diǎn):
- 對(duì)每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類(lèi),這會(huì)導(dǎo)致類(lèi)的個(gè)數(shù)增加,系統(tǒng)更加龐大,設(shè)計(jì)也更加抽象。
- 父類(lèi)中的抽象方法由子類(lèi)實(shí)現(xiàn),子類(lèi)執(zhí)行的結(jié)果會(huì)影響父類(lèi)的結(jié)果,這導(dǎo)致一種反向的控制結(jié)構(gòu),它提高了代碼閱讀的難度。
5.使用場(chǎng)景
- 算法的整體步驟很固定,但其中個(gè)別部分易變時(shí),這時(shí)候可以使用模板方法模式,將容易變的部分抽象出來(lái),供子類(lèi)實(shí)現(xiàn)。
- 需要通過(guò)子類(lèi)來(lái)決定父類(lèi)算法中某個(gè)步驟是否執(zhí)行,實(shí)現(xiàn)子類(lèi)對(duì)父類(lèi)的反向控制。
6.JDK源碼解析
InputStream類(lèi)就使用了模板方法模式。在InputStream類(lèi)中定義了多個(gè) read()
方法,如下:
public abstract class InputStream implements Closeable {
//抽象方法,要求子類(lèi)必須重寫(xiě)
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read(); //調(diào)用了無(wú)參的read方法,該方法是每次讀取一個(gè)字節(jié)數(shù)據(jù)
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
}
從上面代碼可以看到,無(wú)參的 read()
方法是抽象方法,要求子類(lèi)必須實(shí)現(xiàn)。而 read(byte b[])
方法調(diào)用了 read(byte b[], int off, int len)
方法,所以在此處重點(diǎn)看的方法是帶三個(gè)參數(shù)的方法。
在該方法中第18行、27行,可以看到調(diào)用了無(wú)參的抽象的 read()
方法。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-647721.html
總結(jié)如下: 在InputStream父類(lèi)中已經(jīng)定義好了讀取一個(gè)字節(jié)數(shù)組數(shù)據(jù)的方法是每次讀取一個(gè)字節(jié),并將其存儲(chǔ)到數(shù)組的第一個(gè)索引位置,讀取len個(gè)字節(jié)數(shù)據(jù)。具體如何讀取一個(gè)字節(jié)數(shù)據(jù)呢?由子類(lèi)實(shí)現(xiàn)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-647721.html
到了這里,關(guān)于Gof23設(shè)計(jì)模式之模板方法模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!