模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
这个模板是用来创建一个算法的模板。模板就是一个方法。这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。
模板方法被声明为final,避免子类改变这个算法的顺序。在这个模板方法中,算法内的每个步骤都被一个方法代表了,某些方法(通用部分)有这个超类处理;而另一些方法则有子类处理。需要由子类提供的方法,必须在超类中声明为抽象。
对模板方法进行挂钩
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩(子类可以控制算法的步骤)。
当子类必须提供算法中某个方法或步骤的实现时,就使用抽象方法。如果算法的这个部分是可选的,就用钩子。如果是钩子,子类可以选择实现这个钩子,但并不强制这么做。子类可以视情况决定要不要覆盖它们。
钩子可以让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以对此钩子置之不理。钩子能够让子类能够有机会对模板方法中的某些即将发生的(或刚刚发生的)步骤作出反应。
需求实例:定义一个泡茶或咖啡的模板方法(流程算法)。
1、模板方法
//定义抽象类
public abstract class CaffeineBeverageWithHook {
//定义模板方法
void prepareRecipe(){
//把水煮沸
boilWater();
//泡茶或咖啡
brew();
//倒入杯中
pourIncup();
//钩子方法
if(customerWantsCondiments()){
//加入调料
addCondiments();
}
}
//这两个抽象方法由子类实现
abstract void brew();
abstract void addCondiments();
//通用的方法
void boilWater(){
System.out.println("Boiling water");
}
void pourIncup(){
System.out.println("pour into cup");
}
//钩子方法:默认不做事的方法。这是一个具体的方法,子类视情况是否覆盖它
boolean customerWantsCondiments(){
return true;
}
}
2、子类实现抽象方法,覆盖钩子方法:
public class CaffeeHook extends CaffeineBeverageWithHook {
//实现抽象方法
public void brew(){
System.out.println(" coffee brew");
}
public void addCondiments(){
System.out.println("add condiments");
}
//覆盖钩子方法
public boolean customerWantsCondiments(){
String answer=getUserInput();
if(answer.startsWith("y")){
return true;
}else {
return false;
}
}
private String getUserInput(){
return "yes";
}
}