概念
在日常行为中,我们做一些事是有固定的流程的,比如做菜:买菜-洗菜-煮菜-摆盘;流程是固定的,各个步骤却是有差异化的:a在这个菜市场买菜,b在那个菜市场买菜;a开着水龙头清洗,b放在清水里…模板模式就是在编程中体现上述的案例。
角色
模板模式有2类角色:
抽象类:包含一个final修饰的模板方法(不可被重写,对应于上面的固定流程),和若干抽象方法(模板方法里的若干步骤)
具体类:继承抽象类,实现抽象方法。
代码实现
我们以做一份西红柿炒鸡蛋为例,
抽象类:
public abstract class Cook {
//放油
public abstract void oil();
//放鸡蛋
public abstract void egg();
//放西红柿
public abstract void tomato();
//模板方法
public final void cook() {
this.oil();
this.egg();
this.tomato();
}
}
具体类a:
public class MeCook extends Cook {
@Override
public void oil() {
System.out.println("自己:放1斤油");
}
@Override
public void egg() {
System.out.println("自己:放1个蛋");
}
@Override
public void tomato() {
System.out.println("自己:放1个西红柿");
}
}
具体类b:
public class ChefCook extends Cook {
@Override
public void oil() {
System.out.println("大厨:放适量油");
}
@Override
public void egg() {
System.out.println("大厨:放适量鸡蛋");
}
@Override
public void tomato() {
System.out.println("大厨:放适量西红柿");
}
}
测试实际做一份西红柿鸡蛋:
public class Test {
public static void main(String[] args) {
Cook cook1 = new MeCook();
cook1.cook();
Cook cook2 = new ChefCook();
cook2.cook();
}
}
运行结果如下:
优缺点
优点:
a.封装不变部分,扩展可变部分;
b.提取公共代码,便于维护;
c.父类定义行为,子类实现具体步骤。
缺点:
每一个不同的实现就需要一个子类,会造成类的个数增加,系统变得庞大。
钩子函数
钩子函数是给子类的一个授权,用来自定义模板方法的执行逻辑。我们把上面的代码稍作修改。
抽象类:
public abstract class Cook {
//放油
public abstract void oil();
//放鸡蛋
public abstract void egg();
//放西红柿
public abstract void tomato();
private boolean addOil = true;
//钩子函数
public void isAddOil(boolean addOil) {
this.addOil = addOil;
}
//模板方法
public final void cook() {
if(this.addOil) {
this.oil();
}
this.egg();
this.tomato();
}
}
具体类a、b同上:
测试类:
public class Test {
public static void main(String[] args) {
Cook cook1 = new MeCook();
cook1.isAddOil(false);
cook1.cook();
Cook cook2 = new ChefCook();
// 默认是放油的
cook2.cook();
}
}
运行结果如下(自己不放油):