很容易理解,将一系列行为封装成一个模板, 这个模板可以被各种具体的行为调用。模板包含的行为可以是通用的, 也可以是根据具体应用有所不同的。当具体应用不同时,行为定义为抽象的,这样在子类中可以自由实现。
例子: 炒菠菜和炒芹菜, 步骤都是: 开火 -> 放油 -> 放菜(不同实现) ->加盐
于是我们有基类:
public abstract class StirFry {
public void prepareStirFry() {
openFire();
addOil();
addVegetable();
addSalt();
}
public void openFire() {// open fire}
public void addOil() {//add oil}
abstract void addVegetable();
public void addSalt() {//add salt}
}
具体使用时,有两个子类炒菠菜和炒芹菜, 只需事先addVegatable()方法即可,实现了部分解耦:
public class SpinachStirFry extends StirFry {
pubic void addVegetable() { // add spinach}
}
public class CeleryStirFry extends StirFry {
public void addVegetable() {// add celery}
}
这样,具体的方法实现就利用了StirFry这个基类模板。
hook: hook用来自定义如何调用模板方法。 比如在炒菜时,有时需要加辣椒,有时不需要。 一个hook方法:isPepperNeeded() 可以让基类定义一个默认的执行,但是子类可以自定义是否执行此方法。
重写StirFry:
public abstract class StirFry {
public void prepareStirFry() {
openFire();
addOil();
addVegetable();
addSalt();
if (isPepperNeeded()) {
addPepper();
}
}
public void openFire() {// open fire}
public void addOil() {//add oil}
abstract void addVegetable();
public void addSalt() {//add salt}
public void addPepper() {//add pepper}
public boolean isPepperNeeded() {return true;}
}
我们炒菠菜不要辣椒,炒芹菜问用户要不要辣椒。可以这样实现:
public class SpinachStirFry extends StirFry {
public void addVegetable() { // add spinach}
@Override
public boolean isPepperNeeded() {return false;}
}
public class CeleryStirFry extends StirFry {
public void addVegetable() {// add celery}
@Override
public boolean isPepperNeeded() {
// Ask customer
// return customer's response
}
}
在这个例子中,hook方法用来控制需不需要执行某步, hook方法也可以用来控制步骤参数,优先级,等等。
在模板方法模式中,模板的设计是关键。如果太细,则需要太多的钩子方法来控制席位的差别。如果太粗,则大部分方法都要重写,则没有彰显模板方法模式的优越性。
总体来说,模板方法的精髓是: 高级类(StirFry)控制主要步骤,当需要具体化实现时,再询问衍生类。 这样避免了大量无意义的相互方法调用。