定义: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
分析: 这个模式是用来创建一个算法的模板。模板即使一个方法,具体一点就是,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这可以确保算法的结构保持不变同时由子类提供部分实现。
UML类图
AbstractClass: 抽象类,包含了模板方法templateMethod,该方法在实现算法的过程中,用到了两个原语操作operation1和operation2
ConcreteClass: 具体类,实现抽象方法,当模板方法需要这两个抽象方法时,会调用它们。
示例
抽象类
public abstract class CaffeineBeverage {
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
addCondiments();
}
public abstract void brew();
public abstract void addCondiments();
public void boilWater(){
System.out.println("烧水");
}
public void pourInCup(){
System.out.println("倒入杯中");
}
}
实现类
public class Coffee extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("浓缩咖啡");
}
@Override
public void addCondiments() {
System.out.println("添加牛奶,糖");
}
}
public class Tea extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("放入茶包");
}
@Override
public void addCondiments() {
System.out.println("添加柠檬");
}
}
测试
public class Test {
public static void main(String[] args) {
Tea tea = new Tea();
tea.prepareRecipe();
System.out.println(" ");
Coffee coffee = new Coffee();
coffee.prepareRecipe();
}
}
钩子: 在抽象类里,有时候我们会定义一个“钩子”方法,它是空的或者默认的实现。而钩子的存在,可以让子类由能力对算法的不同点进行挂钩,是否挂钩由子类决定。
钩子示例:
抽象类
public abstract class BaverageWithHook {
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
if(customerWantsCondiments()){
addCondiments();
}
}
public abstract void brew();
public abstract void addCondiments();
public void boilWater(){
System.out.println("烧水");
}
public void pourInCup(){
System.out.println("倒入杯中");
}
public boolean customerWantsCondiments(){
return true;
}
}
具体类
public class TeaWithHook extends BaverageWithHook {
@Override
public void brew() {
System.out.println("放入茶包");
}
@Override
public void addCondiments() {
System.out.println("添加柠檬");
}
public boolean customerWantsCondiments(){
String anser = getUserInput();
if(anser.toLowerCase().startsWith("y")){
return true;
} else {
return false;
}
}
public String getUserInput(){
String anser = null;
System.out.println("是否添加柠檬(y/n)?");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
anser = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if(anser == null){
return "no";
}
return anser;
}
}
测试
我们可以看到,钩子可以作为条件控制,影响抽象类中的算法流程,可以让子类实现算法中可选的部分。
设计原则: 别调用我们,我们会调用你。此原则下,我们允许底层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎么使用这些底层组件。