1.定义
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
简单来说:模板方法模式就是定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2.概述
类中的方法用以表明该类的实例所具有的行为,一个类可以有许多方法,而且类中的实例方法可以调用类中的其他若干个方法。在编写类的时候,可能需要将类的许多方法集成到一个实例方法中,即用一个实例方法封装若干个方法的调用,以此表示一个算法的骨架,也就是说,调用实例方法相当于按着一定的顺序执行若干个方法。
模板方法是关于怎样将若干个方法集成到一个方法中,以便形成一个解决问题的算法骨架。模板方法的关键是在一个抽象类中定义一个算法的骨架,即若干个方法集成到一个方法中,并称该方法为一个模板方法,或简称为模板。模板方法所调用的其他方法通常为抽象的方法,这些抽象方法相当于算法骨架的各个步骤,这些步骤的实现可以由子类去完成。
3.应用场景
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。
4.模式的结构与使用
模板方法模式包括两种角色。
1.抽象模板(AbstractTemplate):抽象模板是一个抽象类。抽象模板定义了若干个方法以表示一个算法的各个步骤,这些方法中有抽象方法也有非抽象方法,其中的抽象方法称作为原语操作(Primitive Operation)。重要的一点是,抽象模板中还定义了一个称作模板方法的方法,该方法不仅包含有抽象模板中表示算法步骤的方法调用,而且也可以包含有定义在抽象模板中的其他对象的方法调用,即模板方法定义算法的骨架。
2.具体模板(ConcreteTemplate) :具体模板是抽象模板的子类,实现抽象模板的原语操作。
1.模板方法模式的UML类图
2.结构的描述
以下通过一个简单的问题来描述怎样使用模板方法模式,这个简单的问题就是:显示某个目录下全部文件的名字,比如可以按文件的大小顺序,按最后修改的时间顺序或按文件名字的字典顺序来显示某个目录下全部文件的名字。
1.抽象模板(AbstractTemplate)
本问题中,抽象模板(Abstracttemplate)角色是AbstractTemplate类。抽象模板中的模板方法是showFileName();抽象模板中表示具体步骤的方法是sort()与printFiles()方法,二者都是原语操作。具体的代码如下所示:
import java.io.File;
public abstract class AbstractTemplate {
File[] allFiles;
File dir;
public AbstractTemplate(File dir) {
this.dir = dir;
}
public final void showFileName(){
allFiles=dir.listFiles();
sort();
printFiles();
}
public abstract void printFiles();
public abstract void sort();
}
2.具体模板
对于本问题,具体模板(ConcreteTemplate)是ConcreteTemplate1与ConcreteTemplate2类。ConcreteTemplate2中的sort()方法把目录下的文件名字按其所引用文件的大小顺序排序;ConcreteTemplate1中的sort()方法把目录下的文件名字按其所引用文件被最后修改的时间排序。具体代码如下所示:
ConcreteTemplate1.java
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ConcreteTemplate1 extends AbstractTemplate{
public ConcreteTemplate1(File dir) {
super(dir);
}
@Override
public void sort() {
for(int i=0;i<allFiles.length;i++){
for(int j=i+1;j<allFiles.length;j++){
if(allFiles[j].lastModified()<allFiles[i].lastModified()){
File file=allFiles[i];
allFiles[i]=allFiles[j];
allFiles[j]=file;
}
}
}
}
@Override
public void printFiles() {
for(int i=0;i<allFiles.length;i++){
long time = allFiles[i].lastModified();
Date date=new Date(time);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(date);
String name=allFiles[i].getName();
System.out.println((i+1)+""+name+"("+str+")");
}
}
}
ConcreteTemplate2.java
import java.io.File;
public class ConcreteTemplate2 extends AbstractTemplate{
public ConcreteTemplate2(File dir) {
super(dir);
}
@Override
public void sort() {
for (int i=0;i<allFiles.length;i++){
for(int j=i+1;j<allFiles.length;j++){
if(allFiles[j].length()<allFiles[i].length()){
File file=allFiles[j];
allFiles[j]=allFiles[i];
allFiles[i]=file;
}
}
}
}
@Override
public void printFiles() {
for (int i = 0; i < allFiles.length; i++) {
long fileSize = allFiles[i].length();
String name = allFiles[i].getName();
System.out.println((i+1)+""+name+"("+fileSize+")");
}
}
}
3.测试程序
package com.xing.template;
import java.io.File;
public class Application {
public static void main(String[] args) {
//这里的目录可以自定义,而定义的dir不同,显示的结果也不同
File dir=new File("d:/");
AbstractTemplate template=new ConcreteTemplate1(dir);
System.out.println(dir.getPath()+"目录下的文件:");
template.showFileName();
template=new ConcreteTemplate2(dir);
System.out.println(dir.getPath()+"目录下的文件:");
template.showFileName();
}
}
5.模板方法模式的优点
1.可以通过在抽象模板中定义模板方法给出成熟的算法步骤,同时又不限制步骤的细节,具体模板实现算法细节不会改变整个算法的骨架。
2.在抽象模板中,可以通过钩子方法对某些步骤进行挂钩,具体模板通过钩子可以选择算法骨架中的某些步骤。