概念
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
使用场景
1)多个子类有公有的方法,并且逻辑基本相同时。
2)重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
3)重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
抽象模板的方法分两类:
1)基本方法:也叫基本操作,是由子类实现的方法,并且在模板方法被调用。
2)模板方法:可以有个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。如下:
//抽象模板类
public abstract class AbstractClass {
//基本方法
protected abstract void doSomething();
//基本方法
protected abstract void doAnything();
//模板方法
public void templateMethod(){
//调用基本方法,完成相关的逻辑
this.doAnything();
this.doSomething();
}
}
举例:设计汽车
//抽象模板类
public abstract class HummerModel {
//开车
protected abstract void start();
//停车
protected abstract void stop();
//出喇叭声音
protected abstract void alarm();
//发出引擎声
protected abstract void engineBoom();
final public void run(){
this.start();
this.engineBoom();
if(this.isAlarm()){
this.alarm();
}
this.stop();
}
//钩子方法,默认喇叭是会响的
protected boolean isAlarm(){
return true;
}
}
public class HummerH1 extends HummerModel{
private boolean alarmFlag=true;//要响喇叭
@Override
protected void start() {
System.out.println("悍马H1发动");
}
@Override
protected void stop() {
System.out.println("悍马H1停车");
}
@Override
protected void alarm() {
System.out.println("悍马H1鸣笛");
}
@Override
protected void engineBoom() {
System.out.println("悍马H1引擎声音...");
}
protected boolean isAlarm(){
return this.alarmFlag;
}
//要不要响喇叭,由客户来决定的
public void setAlarm(boolean isAlarm) {
this.alarmFlag = isAlarm;
}
}
public class HummerH2 extends HummerModel{
@Override
protected void start() {
System.out.println("悍马H2发动");
}
@Override
protected void stop() {
System.out.println("悍马H2停车");
}
@Override
protected void alarm() {
System.out.println("悍马H2鸣笛");
}
@Override
protected void engineBoom() {
System.out.println("悍马H2引擎声音...");
}
@Override
protected boolean isAlarm() {
return false;
}
}
//测试
public class Client {
public static void main(String[] args) throws IOException {
System.out.println("H1型号是否需要喇叭声响?0-不需要 1-需要");
String type=(new BufferedReader(new InputStreamReader(System.in))).readLine();
HummerH1 h1 = new HummerH1();
if(type.equals("0")){
h1.setAlarm(false);
}
h1.run();
System.out.println("\n------H2型号--------");
HummerH2 h2 = new HummerH2();
h2.run();
}
}
测试结果:
H1型号是否需要喇叭声响?0-不需要 1-需要
1
悍马H1发动
悍马H1引擎声音...
悍马H1鸣笛
悍马H1停车
------H2型号--------
悍马H2发动
悍马H2引擎声音...
悍马H2停车
H1型号是否需要喇叭声响?0-不需要 1-需要
0
悍马H1发动
悍马H1引擎声音...
悍马H1停车
------H2型号--------
悍马H2发动
悍马H2引擎声音...
悍马H2停车
分析:H1型号汽车是由客户控制是否要想鸣笛,也就是说外界条件改变,影响到模板方法的执行。抽象类中isAlarm的返回值就是影响模板方法的执行结果,这个方法也叫钩子方法。
模板模式的优缺点
优点:1 封装不变部分,扩展可变部分. 2 提取公共部分代码,便于维护. 3 行为由父类控制,子类实现.
缺点:模板方法会带来代码阅读的难度,会让用户觉得难以理解。