案例
经常做饭的同学都比较熟悉炒菜的流程,主流程是热锅、热油、加配料、放菜翻炒、装碟,每道菜的制作流程基本一致,但是每个步骤对每道菜来讲是不同的,现在要抄两道菜,一是酸辣土豆丝,制作流程:热锅、加豆油、加辣椒和醋、放入土豆丝翻炒、装碟;二是西红柿炒蛋:热锅、加菜籽油、加鸡蛋、放入西红柿翻炒、装碟。
以上描述了案例基本需求,下面先介绍模板方法模式的定义,然后用此模式实现案例需求。
模板方法模式
在一个方法里定义一套算法的骨架并把算法的细节部分委托给子类实现,也就是说,子类实现算法的细节步骤而不会改变算法的整体骨架。
此模式的抽象实现
- 首先定义一个抽象类,包含一个final 方法定义算法的骨架,抽象类还包含了算法骨架的细节步骤方法,包含抽象方法和非抽象方法。
- 定义具体实现类,继承抽象类,实现抽象类的抽象方法,也可以覆盖非抽象方法。
拿我们上面的案例来说明,首先定义抽象类 ChaoCai
,炒菜的主流程封装的在抽象类的 final 方法里,再定义两个实现类 ChaoTuTou
和XiHongShiChaoDan
案例模板方法的实现
public abstract class ChaoCai {
public final void chao() {
reGuo();
jiaYou();
jiaCaiLiao();
fangCaiFanChao();
zhuangDie();
}
//装碟
protected abstract void zhuangDie();
//放菜翻炒
protected abstract void fangCaiFanChao();
//加材料
protected abstract void jiaCaiLiao();
//加油
protected abstract void jiaYou();
//热锅
protected void reGuo() {
System.out.println("开火热锅...");
}
}
//酸辣土豆丝
public class ChaoTuDou extends ChaoCai {
@Override
protected void zhuangDie() {
System.out.println("装大碟");
}
@Override
protected void fangCaiFanChao() {
System.out.println("放土豆丝");
}
@Override
protected void jiaCaiLiao() {
System.out.println("放辣椒和醋");
}
@Override
protected void jiaYou() {
System.out.println("加豆油");
}
}
public class XiHongShiChaoDan extends ChaoCai {
@Override
protected void zhuangDie() {
System.out.println("装小盘子");
}
@Override
protected void fangCaiFanChao() {
System.out.println("加西红柿");
}
@Override
protected void jiaCaiLiao() {
System.out.println("加入鸡蛋");
}
@Override
protected void jiaYou() {
System.out.println("加菜子油");
}
}
public class ChaoCaiTest {
public static void main(String[] args) {
ChaoCai chaoCai = new ChaoTuDou();
chaoCai.chao();
chaoCai = new XiHongShiChaoDan();
chaoCai.chao();
}
}
输出结果:
开火热锅…
加豆油
放辣椒和醋
放土豆丝
装大碟
开火热锅…
加菜子油
加入鸡蛋
加西红柿
装小盘子
Java 类库模板方法模式的应用
在 java.util.AbstractList 中的 addAll
方法使用了模板方法,代码如下:
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
其中 add
方法定义如下,目的是让子类覆盖实现
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
总结
模板方法模式提升代码复用并解耦代码实现,但缺点是利用继承,违反了组合优于继承
原则,此模式在框架(Spring 、Mybatis) 出现的频率很高,框架利用此模式定义一套业务的骨架,让子类是定制化具体的业务行为,父类利用final 修饰来防止子类更改算法的或业务的骨架。