現(xiàn)實(shí)生活中經(jīng)常存在這樣的場(chǎng)景,某件事情的基本流程已定铭污,但每步或其中幾步流程具體如何實(shí)施卻可自由發(fā)揮,這種場(chǎng)景映射到設(shè)計(jì)模式中就是模板方法膀篮,或者Template method
使用場(chǎng)景
當(dāng)某個(gè)流程或算法的大致流程已定嘹狞,但其中的某些步驟的實(shí)現(xiàn)需(或最好)推遲至其子類進(jìn)行實(shí)現(xiàn);此時(shí)即考慮使用模板方法模式誓竿;同時(shí)在前述場(chǎng)景下又可進(jìn)行進(jìn)一步細(xì)分:
- 流程中大概的步驟已經(jīng)固定磅网,具體流程實(shí)現(xiàn)者只是定制特定步驟的實(shí)現(xiàn),而不改變整體的流程
- 流程中大概的步驟已經(jīng)固定筷屡,具體流程實(shí)現(xiàn)者不但可以定制特定步驟的實(shí)現(xiàn)涧偷,還能控制流程中某些步驟選擇性執(zhí)行
對(duì)于第二種細(xì)分場(chǎng)景簸喂,我們可以通過(guò)一種稱之為鉤子(hook)的方法進(jìn)行流程控制
代碼示例
首先假設(shè)有一個(gè)基本流程的定義類TemplateInterface
,在基本流程方法templateMethod()
中定義了執(zhí)行的基本步驟燎潮,在步驟方法中喻鳄,step1()
與step3()
已有默認(rèn)的實(shí)現(xiàn),而step2()
與step4()
是抽象方法确封,需在子類中實(shí)現(xiàn)除呵,并且step4()
不屬于必須執(zhí)行的步驟,所以就提供了一個(gè)鉤子方法shouldDoStep4()
以供子類控制step4()
執(zhí)行與否
public abstract class TemplateInterface {
private void step1() {
System. out.println("TemplateInterface step1" );
}
public abstract void step2();
private void step3() {
System. out.println("TemplateInterface step3" );
}
public abstract void step4();
public boolean shouldDoStep4() {//鉤子方法
return true ;
}
public final void templateMethod() {
//template begin
step1();
step2();
step3();
if(shouldDoStep4()){//鉤子
step4();
}
//template ends
}
}
再來(lái)看模板的第一個(gè)子類爪喘,暫且稱之為子模板1颜曾,它重寫了步驟方法step2()
與step4()
以及鉤子方法shouldDoStep4()
,可以發(fā)現(xiàn)在子模板1中秉剑,step4()
是需要執(zhí)行的
public class TemplateImplements_1 extends TemplateInterface{
@Override
public void step2() {
System. out.println("TemplateImplements_1 step2" );
}
@Override
public void step4() {
System. out.println("TemplateImplements_1 step4" );
}
public boolean shouldDoStep4() {
return true ;
}
}
然后來(lái)看模板的另外一個(gè)子類泛豪,暫且稱之為子模板2,它也重寫了步驟方法step2()
與step4()
以及鉤子方法shouldDoStep4()
侦鹏,不同的是诡曙,在模板2的使用場(chǎng)景下,step4()
是不需要執(zhí)行的
public class TemplateImplements_2 extends TemplateInterface{
@Override
public void step2() {
System. out.println("TemplateImplements_2 step2" );
}
@Override
public void step4() {
System. out.println("TemplateImplements_2 step4" );
}
public boolean shouldDoStep4() {
return false ;
}
}
最后來(lái)看調(diào)用結(jié)果
public class TemplateTest {
public static void main(String[] args) {
TemplateInterface templateImplements_1 = new TemplateImplements_1();
System.out.println("template 1 begin");
templateImplements_1.templateMethod();
System.out.println("template 1 end");
TemplateInterface templateImplements_2 = new TemplateImplements_2();
System.out.println();
System.out.println("template 2 begin");
templateImplements_2.templateMethod();
System.out.println("template 2 end");
}
}
//運(yùn)行結(jié)果
template 1 begin
TemplateInterface step1
TemplateImplements_1 step2
TemplateInterface step3
TemplateImplements_1 step4
template 1 end
template 2 begin
TemplateInterface step1
TemplateImplements_2 step2
TemplateInterface step3
template 2 end
可以發(fā)現(xiàn),模板1與模板2分別就特定步驟完成了自己的實(shí)現(xiàn)尔破,并且通過(guò)鉤子方法,模板2可控制自己的執(zhí)行流程里沒(méi)有step4()
基于模板方法模式,父類控制流程以及公共行為龄捡,子類負(fù)責(zé)具體實(shí)現(xiàn),實(shí)現(xiàn)代碼復(fù)用践瓷,同時(shí)子類還可通過(guò)hook實(shí)現(xiàn)反向控制耕驰,模板方法模式很好的體現(xiàn)了開(kāi)閉原則(OCP)