定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构既可以重定义该算法的某些特定步骤
通用代码
抽象模板类
public abstract class AbstractClass {
// 基本方法
protected abstract void doSomething();
// 基本方法
protected abstract void doAnything();
// 模板方法
public final void templateMethod() {
/*
* 调用基本方法,完成相关的逻辑
*/
this.doSomething();
this.doSomething();
}
}
具体模板类
public class ConcreteClass1 extends AbstractClass {
// 基本方法
protected abstract void doSomething() {
// 业务逻辑
}
// 基本方法
protected abstract void doAnything() {
// 业务逻辑
}
}
public class ConcreteClass2 extends AbstractClass {
// 基本方法
protected abstract void doSomething() {
// 业务逻辑
}
// 基本方法
protected abstract void doAnything() {
// 业务逻辑
}
}
场景类
public class Client {
public static void main(String[] args) {
AbstractClass class1 = new ConcreteClass1();
AbstractClass class2 = new ConcreteClass2();
// 调用模板方法
class1.templateMethod();
class2.templateMethod();
}
}
注意:模板中的基本方法尽量设计为protected类型,模板方法都加上final关键字,防止被覆写
优点
- 封装不变部分,扩展可变部分
- 提取公共部分代码,便于维护
- 行为由父类控制,子类实现
缺点
- 子类对父类产生影响,在复杂的项目里面带来代码阅读难度,而且给新手产生不适感。
使用场景
- 多个子类有公共方法,而且逻辑基本相同时
- 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能由各个子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
拓展
加入钩子函数,拓展抽象模板类
public class ConcreteClass1 extends AbstractClass {
// 基本方法
protected abstract void doSomething() {
// 业务逻辑
}
// 基本方法
protected abstract void doAnything() {
// 业务逻辑
// ...
if (this.isAlarm()) {
// 相关业务逻辑
}
// ... 继续业务逻辑
}
// 钩子方法, 默认返回ture
protected boolean isAlarm() {
return true;
}
}
拓展的具体模板类
public class ConcreteClass1 extends AbstractClass {
private boolean alarmFlag = true;
// 基本方法
protected abstract void doSomething() {
// 业务逻辑
}
// 基本方法
protected abstract void doAnything() {
// 业务逻辑
}
// 覆写钩子函数
protected boolean isAlarm() {
return this.alarmFlag;
}
public void setAlarm(boolean isAlarm) {
this.alarmFlag = isAlarm;
}
}
public class ConcreteClass2 extends AbstractClass {
// 基本方法
protected abstract void doSomething() {
// 业务逻辑
}
// 基本方法
protected abstract void doAnything() {
// 业务逻辑
}
protected boolean isAlarm() {
return false;
}
}
特点:
- 通过外部条件改变,可以改变模板方法的执行,抽象类中的isAlarm返回值影响了模板方法的执行结果。有了钩子函数的模板方法模式才完美。
- 由子类的一个方法返回值决定公共部分的执行结果
- 模板方法模式可以使子类编程填空题
参考
《设计模式之禅》