模板方法模式定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的条件下,重新定义算法中的某些步骤
例如:准备一杯咖啡与准备一杯柠檬茶有很多相同步骤:
准备咖啡:烧水- 冲泡咖啡 - 倒入杯中 - 加糖
准备柠檬茶:烧水- 冲泡茶 - 倒入杯中 - 加柠檬
public class Coffee {
public void boilWater(){};
public void makeCoffee(){};
public void pourInCup(){};
public void addSugar(){};
public void prepareCoffee(){
boilWater();
makeCoffee();
pourInCup();
addSugar();
};
}
通常的做法是抽象出一个共同的父类,将相同的步骤移至父类中:
public class Beverage {
public void boilWater(){};
public void pourInCup(){};
}
public class Coffee extends Beverage{
public void makeCoffee(){};
public void addSugar(){};
public void prepareCoffee(){
boilWater();
makeCoffee();
pourInCup();
addSugar();
};
}
简洁多了,但是仔细观察,冲泡咖啡与冲泡茶可以抽象为冲泡方法,加糖与加柠檬可以抽象为加配料方法:
public abstract class Beverage {
public void boilWater(){};
public abstract void make();
public void pourInCup(){};
public abstract void add();
}
public class Coffee extends Beverage{
public void make(){
System.out.println("make coffee");
};
public void add(){
System.out.println("add sugar");
};
public void prepareCoffee(){
boilWater();
this.make();
pourInCup();
this.add();
};
}
此时已经可以清楚的发现,prepareCoffee与prepareTea的步骤已经完全一样了,可抽象至共同父类Beverage中
public abstract class Beverage {
public void boilWater(){};
public abstract void make();
public void pourInCup(){};
public abstract void add();
public void prepare(){
boilWater();
make();
pourInCup();
add();
};
}
public class Coffee extends Beverage{
public void make(){
System.out.println("make coffee");
};
public void add(){
System.out.println("add sugar");
};
}
如果想要实现特定的准备咖啡流程,只需在Coffee类中重写Beverage的prepare方法即可
如果想要Beverage类所有子类的准备流程(必须严格按照烧水 - 冲泡 - 倒入杯中 - 加配料这一流程)完全一致,且不允许修改,只需把Beverage类的prepare方法修改为final类型即可
public abstract class Beverage {
public void boilWater(){};
public abstract void make();
public void pourInCup(){};
public abstract void add();
public final void prepare(){
boilWater();
make();
pourInCup();
add();
};
}
为所有的子类提供统一的固定的准备流程,这就是模板方法模式,这里面固定的流程即为模板方法模式定义中的算法骨架
子类可以在不改变算法流程的条件下,重新定义算法中的某些步骤,如:make方法和add方法由子类决定如何实现
上面的设计对流程的控制太过严苛,很难在实际应用中使用,当然通过一些改动,使子类除了能够决定特定步骤的具体实现方式之外,还可以对流程进行控制:
public abstract class Beverage {
public void boilWater(){};
public abstract void make();
public void pourInCup(){};
public abstract void add();
public final void prepare(){
boilWater();
make();
pourInCup();
if(addOrNot()){
add();
}
};
protected boolean addOrNot(){
return true;
}
}
public class Coffee extends Beverage{
public void make(){
System.out.println("make coffee");
};
public void add(){
System.out.println("add sugar");
};
protected boolean addOrNot(){
try {
System.out.println("Have some sugar?Y/N");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String in = reader.readLine();
if(null == in || in.equals("") || in.equals("N")){
return false;
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
测试一下:
public class Test {
public static void main(String[] args) {
Beverage b = new Coffee();
b.prepare();
}
}
make coffee
Have some sugar?Y/N
Y
add sugar
make coffee
Have some sugar?Y/N
N