模板模式
定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
类型
行为型。
例子
举慕课网的例子,当讲师发布新课程时,慕课网一般要求讲师制作PPT、制作视频、编写手记(可选)、打包课程等,所以我们可以将这一过程模板化,可选的操作这里使用钩子方法(也可以在抽象类中不出现,由子类来添加实现即可),不可选或者说必须的操作就直接final
,即不可重写。
ACourse类(课程抽象类),定义了讲师发布新课程时的一些操作。
package com.kaven.design.pattern.behavioral.templatemethod;
public abstract class ACourse {
protected final void makeCourse(){
this.makePPT();
this.makeVideo();
if(needWriteArticle()){
this.writeArticle();
}
this.packageCourse();
}
final void makePPT(){
System.out.println("制作PPT");
}
final void makeVideo(){
System.out.println("制作视频");
}
final void writeArticle(){
System.out.println("编写手记");
}
//钩子方法
protected boolean needWriteArticle(){
return false;
}
abstract void packageCourse();
}
DesignPatternCourse类(设计模式课程类),继承了ACourse类,实现了自己的打包课程方法packageCourse()
,并且需要编写手记,使用钩子方法改变默认行为needWriteArticle()
。
package com.kaven.design.pattern.behavioral.templatemethod;
public class DesignPatternCourse extends ACourse {
void packageCourse() {
System.out.println("提供课程Java源代码");
}
@Override
protected boolean needWriteArticle() {
//需要编写手记
return true;
}
}
FECourse类(前端课程),继承了ACourse类,实现了自己的打包课程方法packageCourse()
,并且不需要编写手记(ACourse类中默认行为)。
package com.kaven.design.pattern.behavioral.templatemethod;
public class FECourse extends ACourse {
void packageCourse() {
System.out.println("提供课程的前端代码");
System.out.println("提供课程的图片等多媒体素材");
}
}
应用层代码:
package com.kaven.design.pattern.behavioral.templatemethod;
public class Test {
public static void main(String[] args) {
System.out.println("后端设计模式课程start——");
ACourse designPatternCourse = new DesignPatternCourse();
designPatternCourse.makeCourse();
System.out.println("后端设计模式课程end——");
System.out.println("前端课程start——");
ACourse fePatternCourse = new FECourse();
fePatternCourse.makeCourse();
System.out.println("前端课程end——");
}
}
输出:
后端设计模式课程start——
制作PPT
制作视频
编写手记
提供课程Java源代码
后端设计模式课程end——
前端课程start——
制作PPT
制作视频
提供课程的前端代码
提供课程的图片等多媒体素材
前端课程end——
从上面的代码例子中,我们可以发现,在定义父类的模板方法的时候,我们将模板方法增加了final修饰,这样做的目的是为了子类对于父类的扩展原则是应该不修改父类原有的基本方法,模板方法在定义上面就是来定义整个框架的,而这个设计也符合设计模式中的“开闭原则”-对扩展开放,对修改关闭
,可选的方法,就可以使用钩子方法。
这里便完成了一个简单的模板模式例子。
应用场景
- 多个产品有相同或者类似的场景。
优点
- 具体细节步骤实现定义在子类中,子类定义详细处理算法是不会改变算法整体结构。
- 存在一种反向的控制结构,通过父类调用其子类的操作,通过子类对父类进行扩展增加新的行为,符合“开闭原则”。
- 提取公共代码,便于维护。
缺点
- 每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大。