現(xiàn)實(shí)生活中經(jīng)常存在這樣的場景,某件事情的基本流程已定,但每步或其中幾步流程具體如何實(shí)施卻可自由發(fā)揮,這種場景映射到設(shè)計(jì)模式中就是模板方法,或者Template method
使用場景
當(dāng)某個(gè)流程或算法的大致流程已定,但其中的某些步驟的實(shí)現(xiàn)需(或最好)推遲至其子類進(jìn)行實(shí)現(xiàn);此時(shí)即考慮使用模板方法模式;同時(shí)在前述場景下又可進(jìn)行進(jìn)一步細(xì)分:
- 流程中大概的步驟已經(jīng)固定,具體流程實(shí)現(xiàn)者只是定制特定步驟的實(shí)現(xiàn),而不改變整體的流程
- 流程中大概的步驟已經(jīng)固定,具體流程實(shí)現(xiàn)者不但可以定制特定步驟的實(shí)現(xiàn),還能控制流程中某些步驟選擇性執(zhí)行
對(duì)于第二種細(xì)分場景,我們可以通過一種稱之為鉤子(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
}
}
再來看模板的第一個(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 ;
}
}
然后來看模板的另外一個(gè)子類,暫且稱之為子模板2,它也重寫了步驟方法step2()與step4()以及鉤子方法shouldDoStep4(),不同的是,在模板2的使用場景下,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 ;
}
}
最后來看調(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),并且通過鉤子方法,模板2可控制自己的執(zhí)行流程里沒有step4()
基于模板方法模式,父類控制流程以及公共行為,子類負(fù)責(zé)具體實(shí)現(xiàn),實(shí)現(xiàn)代碼復(fù)用,同時(shí)子類還可通過hook實(shí)現(xiàn)反向控制,模板方法模式很好的體現(xiàn)了開閉原則(OCP)