1.定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2.适用场景
1)HttpServlet的service()方法。HttpSerlvet在service方法中调用doGet()和doPost()等方法,用户定义的Servlet继承自HttpServlet,重写其中的方法,由父类统一调用子类的方法。
2)Spring JdbcTemplate。execute()方法定义算法的骨架,获取连接,执行具体操作,释放连接。
3.类图
宋丹丹说把大象放入冰箱分3步,
1:冰箱门打开 2:把大奖放进去 3:冰箱门关上。
同样如果把大象放入衣柜里也分3步,
1:把衣柜门打开 2:把大象放进去 3:衣柜们关上。
这个就可以使用模板方法来定义算法的骨架,而具体是把冰箱门打开还是把衣柜门打开,可以放到子类中实现。
1)ElephantTemplateMethod:模板方法抽象类,定义了一个模板方法,定义算法的骨架。
2)Chest、Refrigerator:具体子类,复写父类的方法来实现具体的算法。
3)TemplateMethodMain:客户端。
4.代码示例
public abstract class ElephantTemplateMethod {
public final void putElephant(){
openDoor();
throwinto();
closeDoor();
}
protected abstract void openDoor();
private void throwinto(){
System.out.println("把大象扔进去");
}
protected abstract void closeDoor();
}
public class Chest extends ElephantTemplateMethod{
protected void openDoor(){
System.out.println("把衣柜门打开");
}
protected void closeDoor(){
System.out.println("把衣柜门关上");
}
}
public class Refrigerator extends ElephantTemplateMethod{
protected void openDoor(){
System.out.println("把冰箱门打开");
}
protected void closeDoor(){
System.out.println("把冰箱门关上");
}
}
public class TemplateMethodMain {
public static void main(String[] args) throws Exception{
ElephantTemplateMethod template = new Refrigerator();
template.putElephant();
System.out.println("--------分隔线----------");
template = new Chest();
template.putElephant();
}
}
输出结果:
把冰箱门打开
把大象扔进去
把冰箱门关上
--------分隔线----------
把衣柜门打开
把大象扔进去
把衣柜门关上
5.要点
1)为了防止子类重写父类的算法,可以将模板方法定义为final类型的。
2)抽象类中的方法包括模板方法(定义算法的骨架),抽象方法(由子类负责重写算法),具体方法(不需要子类重写)和钩子方法(由子类决定是否重写)。钩子方法提供了默认实现,这样子类就不需要重写每个方法,节省子类工作量。
3)需要重写的方法一般命名为doxxx,例如HttpServlet中的doGet(),Spring JdbcTemplate execute()方法中的doInStatement()。
6.同策略模式的不同
模板方法模式使用继承来改变算法的一部分,而策略模式使用委托来改变整个算法。