1 基本介绍
定义:一个操作中的算法的框架,将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
UML类图:
模板方法模式包含两种模式:
抽象模板(AbstractClass) 定义一套算法框架/流程
具体实现(ConcreteClass) 对算法框架/流程的某些步骤进行了实现
2 通用代码
2.1 抽象模板类
public abstract class AbstractClass {
// 基本方法
protected abstract void method1();
// 基本方法
protected abstract void method2();
// 模板方法,通常模板方法都会加上final关键字,防止子类对其覆写,并遵守定义算法结构/流程的语义
public final void templateMethod() {
// 调用基本方法,完成相关逻辑
this.method1();
this.method2();
}
}
2.2 具体模板
public class ConcreteClass extends AbstractClass{
@Override
protected void method1() {
// 业务逻辑处理
}
@Override
protected void method2() {
// 业务逻辑处理
}
}
3 案例演示
需求:生产奔驰车,有两个型号A,B,那么就有两套生产的模板。为演示假设车子的功能:启动,熄火,发出喇叭声,引擎声,还有行驶等等。
奔驰车抽象模板:
public abstract class BenChiModel {
// 启动
protected abstract void start();
// 喇叭声
protected abstract void alarm();
// 引擎声
protected abstract void engineBoom();
// 熄火
protected abstract void stop();
// 行驶
public final void run() {
// 调用基本方法,完成相关逻辑
this.start();
this.alarm();
this.engineBoom();
this.stop();
}
}
具体模板A:
public class BenChiModelA extends BenChiModel{
@Override
protected void start() {
System.out.println("A....启动");
}
@Override
protected void alarm() {
System.out.println("A....喇叭声");
}
@Override
protected void engineBoom() {
System.out.println("A....引擎声");
}
@Override
protected void stop() {
System.out.println("A....熄火");
}
}
具体模板B:
public class BenChiModelB extends BenChiModel{
@Override
protected void start() {
System.out.println("B....启动");
}
@Override
protected void alarm() {
System.out.println("B....喇叭声");
}
@Override
protected void engineBoom() {
System.out.println("B....引擎声");
}
@Override
protected void stop() {
System.out.println("B....熄火");
}
}
客户端:
public static void main(String[] args) {
BenChiModelA benchiA = new BenChiModelA();
benchiA.run();
BenChiModelB benchiB = new BenChiModelB();
benchiB.run();
}
演示结果:
4 优缺点
优点
①封装不变部分,扩展可变部分
②提取公共部分代码,便于维护
③行为由父类控制,子类实现
缺点 按照我们正常的写法习惯,抽象类负责声明最抽象、最一般的事物的属性和方法,实现类完成具体的事物的属性和方法,但是模板方法模式却颠倒了,抽象类定义部分抽象方法,由子类实现,子类执行的结果影响父类的结构,也就是子类对付类产生了影响,如果是在复杂的项目中,会增加代码阅读的难度。
5 应用场景
①多个子类有共有的方法,并且逻辑基本相同时。
②重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能由各个子类实现。
③重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数(详见模板方法模式的扩展)来约束行为。
6 模板方法模式的扩展
原有需求修改:客户想要在模型A中,我让它响才响,而在模型B中嫌烦,直接不响
案例代码修改:
抽象模板类:
public abstract class BenChiModel {
// 启动
protected abstract void start();
// 喇叭声
protected abstract void alarm();
// 引擎声
protected abstract void engineBoom();
// 熄火
protected abstract void stop();
// 行驶
public final void run() {
// 调用基本方法,完成相关逻辑
this.start();
if (isAlarm()) {
this.alarm();
}
this.engineBoom();
this.stop();
}
// 钩子函数
protected boolean isAlarm() {
return true;// 车子默认还是响的
}
}
具体模板A:
public class BenChiModelA extends BenChiModel{
private boolean isAlarm = true;
public void setAlarm(boolean isAlarm) { this.isAlarm = isAlarm; }
@Override
protected void start() { System.out.println("A....启动"); }
@Override
protected void alarm() { System.out.println("A....喇叭声"); }
@Override
protected void engineBoom() { System.out.println("A....引擎声"); }
@Override
protected void stop() { System.out.println("A....熄火"); }
@Override
protected boolean isAlarm() { return this.isAlarm; }
}
具体模板B:
public class BenChiModelB extends BenChiModel{
@Override
protected void start() { System.out.println("B....启动"); }
@Override
protected void alarm() { System.out.println("B....喇叭声"); }
@Override
protected void engineBoom() { System.out.println("B....引擎声"); }
@Override
protected void stop() { System.out.println("B....熄火"); }
// 客户要求:模型B的喇叭是不响的
@Override
protected boolean isAlarm() { return false; }
}
客户端及演示结果:
个人理解 模板方法模式:父类建立框架/规则/算法,子类在重写父类部分的方法后,再调用从父类继承的方法,产生不同的结果。