概念
Template Method
(模板方法):
例如做咖啡和茶是有类似的过程的:
- 烧水
- 混合(放入咖啡或者茶叶)
- 倒入杯子
- 添加一些附加材料(糖或者其他)
其中步骤2和4有些许不同。我们在写这样的一个类,如果分开写,1,4步骤的代码要被重复写两次。所以可以使用模板模式,写一个咖啡和茶的父类,然后他们都继承这些方法。
实现
// 代码源于Head First Design Pattern 283页
// 咖啡因类饮料的父类。咖啡和茶都可以继承
public abstract class CaffeineBeverage{
//准备
//使用final是防止子类重写该方法。
final void prepareRecipe(){
boilWater();
brew(); //步骤2,混合
porurInCup();
addCondiments(); //步骤4,添加
}
// 把步骤2.4声明为抽象方法,让子类去实现
abstract void brew();
abstract void addCondiments();
//相同的方法
void bolidWater(){
System.out.println("Boiling water")
}
void pourInCup(){
System.out.println("Pouring into cup")
}
}
//子类:Tea
public class Tea extends CaffeineBeverage{
// 重写抽象方法
public void brew(){
System.out.println("Stepping the tea");
}
public void addCondiments(){
System.out.println("Adding Lemon")
}
}
// 子类: Coffee
// 同Tea
比较
使用Template Method
-
能够最大程度对代码进行重用。
-
不变的方法集中在父类中,修改起来简单。
-
提供了其他相类似的子类的接入。只需要实现响应的抽象方法就可以了。
Template Method Method Pattern:
在一个方法里定义一个算法的骨架,其中一些步骤的实现推迟到具体的子类中。模板方法让子类在不改变算法的整体结构情况下,重新定义某些步骤。
Hook(钩子)方法
子类可以重新父类中的hook方法,这些方法能够可能能够改变父类中算法的运行
例如
public abstract class CaffeineBeverage{
//准备
//使用final是防止子类重写该方法。
final void prepareRecipe(){
boilWater();
brew(); //步骤2,混合
porurInCup();
// HOOK方法的一种使用
if(customerWantsCondiments()){
addCondiments(); //步骤4,添加
}
}
// 把步骤2.4声明为抽象方法,让子类去实现
abstract void brew();
abstract void addCondiments();
//相同的方法
void bolidWater(){
System.out.println("Boiling water")
}
void pourInCup(){
System.out.println("Pouring into cup")
}
// hook method,如果子类重写,可以改变prepareRecipe的运行轨迹。
bool customerWantsCondiments(){
return true;
}
}
子类可以通过重写customerWantsCondiments()方法类决定第四步是否添加东西。
可见:
- 抽象的方法子类是必须实现的
- hook方法不一定需要子类重写,是一个可选项。
hook方法的用途:
- 提供给子类去修改算法的可选部分。如上个例子中第四步是可选项。
- 给子类一个机会去对模板方法中刚刚发生或者即将发生的做出反应,例如向屏幕打印运行信息。
Hollywood Principle
不要调用我们,我们将调用你。
在类设计中,高阶组件调用低阶组件,这个低阶组件有调用了某个高阶组件,然后有调用了一些其他的等,这就产生了依赖腐败。
遵循Hollywood设计原则,让低阶组件把他们自己挂在到系统中,高阶组件决定他们什么时候被需要,如何被使用。换句话说,高阶组件告诉低阶组件:不要调用我们,我将调用你
在我们设计模板方法模式时,父类就告诉子类,不要调用我,我将调用你。