在面向对象的开发过程中,通常会遇到这样一个问题,我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序,但是,某些步骤的具体实现是未知的,或者说某些步骤的实现会随着环境的变化而改变。
以泡茶和泡咖啡的例子来理解一下。
泡咖啡的步骤:
- 水烧开
- 冲泡咖啡粉
- 把咖啡倒入被子
- 加糖和加牛奶
泡茶步骤:
- 水烧开
- 冲泡茶叶
- 把茶水倒入被子
- 加柠檬
首先写好执行这两个步骤的类:
咖啡
public class Coffee {
public void prepareRecipe(){
boilWater();
brewCoffee();
pourInCup();
addSugarMilk();
}
public void boilWater(){
}
public void brewCoffee(){
}
public void pourInCup(){
}
public void addSugarMilk(){
}
}
茶:
public class Tea {
public void prepareRecipe(){
boilWater();
brewTea();
pourInCup();
addLemon();
}
public void boilWater(){
}
public void brewTea(){
}
public void pourInCup(){
}
public void addLemon(){
}
}
变化与不变,我们发现在这两个类里面水烧开和将水倒入被子的方法是一样的,所以这两个就可以抽象出来放到公共类里面。
public abstract class HotDrink {
public abstract void prepareRecipe();
public void boilWater(){
}
public void pourInCup(){
}
}
同时我们发现不仅这两个方法是一样的,而且冲泡的步骤也是一样的,同样我们也可以抽象出来。
public abstract class HotDrink {
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
addCondiments();
}
public abstract void brew();
public abstract void addCondiments();
public final void boilWater(){
}
public final void pourInCup(){
}
}
这样模板基本完成了。子类只要关心抽象函数的实现就可以了,他不需要关心步骤和公共的方法。
其实模板模式就是封装了一个算法步骤,并允许子类为一个或多个步骤方法提供实现。模板模式可以使子类在不改变算法结构的情况下,重新定义算法中的某些步骤。
总感觉上面写的还不够灵活 ,要想子类可以控制父类的步骤 怎么办呢?
public abstract class HotDrink {
public final void prepareRecipe(){
boilWater();
brew();
pourInCup();
if(wantCondimentsHook()) {
addCondiments();
}else{
Log.i("","No Condiments");
}
}
public boolean wantCondimentsHook(){
return true;
}
public abstract void brew();
public abstract void addCondiments();
public final void boilWater(){
}
public final void pourInCup(){
}
}
子类可以通过重写wantCondimentsHook()这个方法来改变返回值 从而改变父类的步骤。