模板方法模式定义
Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤)
这样说可能似懂非懂,看下列类图,进一步加深理解
其中,AbstractClass叫做抽象模板,它的方法分为两类:
-
基本方法
基本方法也叫做基本操作,由子类实现,并且在模板方法中被调用 -
模板方法
可以有一个或多个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度, 完成固定的逻辑。
注意: 为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写
类图中的 ConcreteClass1 和 ConcreteClass2 属于具体模板,实现父类所定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现。
示例
以炒菜示例,大致的流程就是先加油,然后加盐,其次放入菜
//抽象美味类
public abstract class Dish {
private void oil(){
System.out.println("加油");
}
protected void yan(){
System.out.println("加盐");
}
protected void done(){
System.out.println("烹饪完成");
}
//主菜
protected abstract void zhucai();
//模板方法
public final void doDish(){
oil();
yan();
zhucai();
done();
}
}
烹饪鸡蛋
public class Eage extends Dish{
@Override void zhucai() {
System.out.println("加蛋");
}
}
烹饪鱼
public class Fish extends Dish{
@Override void zhucai() {
System.out.println("加鱼");
}
}
客户端调用
public class Test {
public static void main(String[] args) {
Dish fish = new Fish();
Dish eage = new Eage();
fish.doDish();
System.out.println("=============");
eage.doDish();
}
}
输出
加油
加盐
加鱼
烹饪完成
=============
加油
加盐
加蛋
烹饪完成
抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或者方法尽量不要设置为protected类型
钩子方法(Hook Method)
所谓的钩子方法,就是说可以通过子类去影响父类模板方法的执行结果
//抽象美味类
public abstract class Dish {
private void oil(){
System.out.println("加油");
}
protected void yan(){
System.out.println("加盐");
}
protected void done(){
System.out.println("烹饪完成");
}
//主菜
protected abstract void zhucai();
//模板方法
public final void doDish(){
oil();
yan();
if (flag()){
zhucai();
}
done();
}
//钩子方法
public boolean flag(){
return true;
}
}
子类
public class Pure extends Dish{
//重写钩子方法
@Override public boolean flag() {
return false;
}
@Override void zhucai() {
}
}
客户端调用
public class Test {
public static void main(String[] args) {
Dish fish = new Fish();
Dish eage = new Eage();
fish.doDish();
System.out.println("=============");
eage.doDish();
System.out.println("=============");
pure.doDish();
}
}
输出
加油
加盐
加鱼
烹饪完成
=============
加油
加盐
加蛋
烹饪完成
=============
加油
加盐
烹饪完成
模板方法的优势
- 行为由父类控制,子类实现
- 提取公共部分代码,便于维护
- 封装不变部分,扩展可变部分
模板方法的缺点
总结
模板方法模式就是在模板方法中按照一定的规则和顺序调用基本方法。
模板方法在一些开源框架中应用非常多,它提供了一个抽象类,然后开源框架写了一堆子类。如果你需要扩展功能,可以继承这个抽象类,然后去覆写protected方法,最后调用一个类似execute方法,就完成了你的扩展开发,是一种非常容易扩展的一种设计模式