模板方法模式是一種行為型設(shè)計(jì)模式闪朱,它比較簡(jiǎn)單怕篷,我們平時(shí)的編程中可能就經(jīng)常用到了它
介紹
定義
模板方法模式(Template Method Pattern)- 定義一個(gè)操作中的算法的框架打瘪,而將一些步驟延遲到子類中友鼻。使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟
簡(jiǎn)單來(lái)說(shuō),就是把可變的部分(方法)放在子類中實(shí)現(xiàn)瑟慈,把不可變的部分放在父類中實(shí)現(xiàn)
舉個(gè)例子桃移,假如你賺錢了買了個(gè)房子,交房之后是個(gè)毛坯需要裝修葛碧,裝修的流程是水電借杰、泥工、木工进泼、再買家具電器等蔗衡,這時(shí)關(guān)于裝修哪種風(fēng)格有了不同意見(jiàn),你自己喜歡簡(jiǎn)約時(shí)尚的風(fēng)格乳绕,而你爸媽喜歡中式風(fēng)格绞惦,可不管是什么風(fēng)格,整個(gè)裝修的流程還是不變的洋措,于是可以找裝修公司制定兩種風(fēng)格的方案济蝉,這其中變化的是兩種風(fēng)格各個(gè)流程的具體材料、做工不同,不變的是裝修的流程
模板方法結(jié)構(gòu)
通用類圖
使用模板方法模式很簡(jiǎn)單王滤,使用Java的繼承機(jī)制即可贺嫂,這里有兩種角色
-
抽象模板(AbstractClass):提供模板方法,讓子類實(shí)現(xiàn)基本方法
-
基本方法:
基本方法也叫做基本操作雁乡,是由子類實(shí)現(xiàn)的方法第喳,并且在模板方法被調(diào)用
-
模板方法:
可以有一個(gè)或幾個(gè),一般是一個(gè)具體方法踱稍,也就是一個(gè)框架曲饱,實(shí)現(xiàn)對(duì)基本方法的調(diào)度,完成固定的邏輯
-
具體模板(ConcreteClass):實(shí)現(xiàn)父類所定義的一個(gè)或多個(gè)抽象方法珠月,也就是父類定義的基本方法在子類中得以實(shí)現(xiàn)
一般模板方法可以用final修飾扩淀,這樣子類不能重寫,避免被修改
優(yōu)點(diǎn)以應(yīng)用場(chǎng)景
優(yōu)點(diǎn)
- 封裝不變部分啤挎,擴(kuò)展可變部分引矩。把認(rèn)為是不變部分的算法封裝到父類實(shí)現(xiàn),而可變部分的則可以通過(guò)繼承來(lái)繼續(xù)擴(kuò)展
- 提取公共部分代碼侵浸,便于維護(hù)
- 行為由父類控制旺韭,子類實(shí)現(xiàn)。子類可以通過(guò)擴(kuò)展的方式增加相應(yīng)的功能掏觉,符合開(kāi)閉原則
應(yīng)用場(chǎng)景
- 多個(gè)子類有公有的方法区端,并且邏輯基本相同時(shí)
- 重要、復(fù)雜的算法澳腹,可以把核心算法設(shè)計(jì)為模板方法织盼,周邊的相關(guān)細(xì)節(jié)功能則由各個(gè)子類實(shí)現(xiàn)
- 重構(gòu)時(shí),模板方法模式是一個(gè)經(jīng)常使用的模式酱塔,把相同的代碼抽取到父類中沥邻,然后通過(guò)鉤子函數(shù)約束其行為
實(shí)例
統(tǒng)計(jì)操作時(shí)間
抽象模板,用于給操作統(tǒng)計(jì)時(shí)間羊娃,其中getTime()
為模板方法唐全,用于統(tǒng)計(jì)操作時(shí)間,該行為交給父類控制蕊玷,code()
鉤子方法延遲到子類中實(shí)現(xiàn)
public abstract class GetTimeTemplate {
/**
* 基本方法邮利,由子類實(shí)現(xiàn) (鉤子方法)
*/
public abstract void code();
/**
* 模板方法 固定流程方法
*/
public long getTime() {
// 獲取起始時(shí)間
long t1 = System.currentTimeMillis();
// 調(diào)用基本方法
code();
// 獲取結(jié)束時(shí)間
long t2 = System.currentTimeMillis();
return t2 - t1;
}
}
具體模板實(shí)現(xiàn) - 統(tǒng)計(jì)復(fù)制文件操作時(shí)間
public class CopyFileDemo extends GetTimeTemplate {
@Override
public void code() {
//復(fù)制文件
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("1.jpg"));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("2.jpg"));
byte[] bs = new byte[256];
int len = 0;
while ((len = inputStream.read(bs)) != -1) {
outputStream.write(bs, 0, len);
outputStream.flush();
}
//釋放資源
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
具體模板實(shí)現(xiàn) - 統(tǒng)計(jì)循環(huán)操作時(shí)間
public class ForDemo extends GetTimeTemplate {
@Override
public void code() {
//輸出for循環(huán)
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
}
}
參考:《設(shè)計(jì)模式之禪》、《大話設(shè)計(jì)模式》