什么是模板模式
模板模式是在一个抽象类中定义了执行它的方法的方式(模板方法),由抽象类的子类根据具体的业务需求去重写父类的中方法,但执行时将调用抽象类中定义的方式进行。
在模板模式中,一个抽象的公开定义了执行它的方法的方式(模板)。它的子类可以重写方法实现,但调用将以抽象类中定义的方法进行。这种类型的设计模式属于行为型模式
使用场景
- 多个子类有共同的方法,且逻辑基本相同
- 可以把核心的算法和重要的功能设计为模板方法,子类去实现相关细节功能
- 系统在进行重构或者是功能优化的时候可以将子类重复的代码抽离到父类中
来看一个场景:
管理系统里面,可能需要导出各种的excel,针对导出的表格,我们需要增加表头,填充正文数据,填充表尾,添加水印等,这是我们就可以使用模板方法
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:44
*/
public abstract class ExcelReport {
public void print() {
printTitle();
printBody();
printTail();
printWatermark();
}
//打印表头
public abstract void printTitle();
//打印正文
public abstract void printBody();
//打印表尾
public abstract void printTail();
//打印水印
public abstract void printWatermark();
}
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:45
*/
public class AReportImpl extends ExcelReport {
//打印表头
public void printTitle() {
System.out.println("打印A表头");
}
//打印正文
public void printBody() {
System.out.println("打印A正文");
}
//打印表尾
public void printTail() {
System.out.println("打印A表尾");
}
//打印水印
public void printWatermark() {
System.out.println("打印A水印");
}
}
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:48
*/
public class BReportImpl extends ExcelReport {
//打印表头
public void printTitle() {
System.out.println("打印B表头,字体 B,大小 B,图标 B ...... 个性化");
}
//打印正文
public void printBody() {
System.out.println("打印B个性化正文");
}
//打印表尾
public void printTail() {
System.out.println("打印B个性化表尾");
}
//打印水印
public void printWatermark() {
System.out.println("打印B个性化水印");
}
}
测试:
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:48
*/
public class Test {
public static void main(String[] argv) {
ExcelReport report = new BReportImpl();
report.print();
}
}
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”
改进上面的案列:
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:44
*/
public abstract class ExcelReport {
public void print() {
printTitle();
printBody();
printTail();
if (ifprintWatermark()) {
printWatermark();
}
}
//打印表头
public abstract void printTitle();
//打印正文
public abstract void printBody();
//打印表尾
public abstract void printTail();
//打印水印
public abstract void printWatermark();
// 钩子方法
boolean ifprintWatermark() {
return true;
}
}
package com.cjian.GOF.template;
/**
* @description:
* @author: CJ
* @time: 2021/10/26 11:48
*/
public class BReportImpl extends ExcelReport {
//打印表头
public void printTitle() {
System.out.println("打印B表头,字体 B,大小 B,图标 B ...... 个性化");
}
//打印正文
public void printBody() {
System.out.println("打印B个性化正文");
}
//打印表尾
public void printTail() {
System.out.println("打印B个性化表尾");
}
//打印水印
public void printWatermark() {
System.out.println("打印B个性化水印");
}
@Override
boolean ifprintWatermark() {
return false;
}
}
钩子方法的作用
1、让子类实现算法中的可选部分。算法中的某些步骤是可选的,子类可以做出决定是否需要这些步骤。
2、如果钩子对于子类的实现不重要时,子类可以对钩子置之不理。
3、钩子可以让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。可以在钩子中实现我们对于某个步骤执行需要作出的动作,模板方法的某个步骤执行时,调用钩子。