模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式适用的设计场景
设计者需要给出一个算法的固定步骤,并将某些步骤的具体实现留给子类来实现。
需要对代码进行重构,将各个子类公共行为提取出来集中到一个共同的父类中以避免代码重复。
模板方法模式的优点
可以通过在抽象模板定义模板方法给出成熟的算法步骤,同时又不限制步骤的细节,具体模板实现算法细节不会改变整个算法的骨架。
在抽象模板模式中,可以通过钩子方法对某些步骤进行挂钩,具体模板通过钩子可以选择算法骨架中的某些步骤。
两个角色
抽象模板(抽象方法、具体方法、模板方法、钩子方法)、具体模板
实例练习
1、显示某个目录下全部文件的名字,比如可以按文件的大小顺序,按最后修改的时间顺序或按文件名字的字典顺序来显示某个目录下全部文件的名字
1)抽象模板
AbstractTemplate.java
package mbffms_1;
import java.io.*;
public abstract class AbstractTemplate {
//抽象模板
File[] allFiles;
File dir;
AbstractTemplate(File dir){
this.dir=dir;
}
public final void showFileName() {//模板方法
allFiles=dir.listFiles();
sort();
printFiles();
}
public abstract void sort();
public abstract void printFiles();
}
2)具体模板
ConcreteTemplate1.java
package mbffms_1;
import java.io.*;
import java.awt.*;
import java.util.Date;
import java.text.SimpleDateFormat;
public class extends AbstractTemplate{
//具体模板
ConcreteTemplate1(File dir) {
super(dir);
}
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[j];
allFiles[j]=allFiles[i];
allFiles[i]=file;
}
}
public void printFiles() {
for(int i=0;i<allFiles.length;i++) {
long time=allFiles[i].lastModified();
Date date=new Date(time);
SimpleDateFormat matter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str=matter.format(date);
String name=allFiles[i].getName();
int k=i+1;
System.out.println(k+" "+name+"("+str+")");
}
}
}
ConcreteTemplate2.java
package mbffms_1;
import java.io.*;
import java.awt.*;
import java.util.Date;
import java.text.SimpleDateFormat;
public class ConcreteTemplate2 extends AbstractTemplate{
//具体模板
ConcreteTemplate2(File dir) {
super(dir);
}
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[j];
allFiles[j]=allFiles[i];
allFiles[i]=file;
}
}
public void printFiles() {
for(int i=0;i<allFiles.length;i++) {
long fileSize=allFiles[i].length();
String name=allFiles[i].getName();
int k=i+1;
System.out.println(k+" "+name+"("+fileSize+"字节)");
}
}
}
3)测试类
package mbffms_1;
import java.io.File;
public class test {
public static void main(String[] args) {
//自己选择文件目录
File dir=new File("e:/面向对象程序设计/面B");
AbstractTemplate template=new ConcreteTemplate1(dir);
System.out.println(dir.getPath()+"目录下的文件:");
template.showFileName();
template=new ConcreteTemplate2(dir);
System.out.println(dir.getPath()+"目录下的文件:");
template.showFileName();
}
}
2、钩子方法运用
钩子方法是抽象模板中定义的具体方法,但给出了空实现或默认的实现,并允许子类重写这个具体方法,允许具体模板对算法的不同点进行挂钩,以确定在什么条件下执行模板方法中的哪些算法步骤,干扰父类算法进程
比如说有一个接口,这个接口里有3个方法,而你只想用其中一个方法,那么这时,你可以写一个抽象类实现这个接口,在这个抽象类里将你要用的那个方法设置为abstract,其它方法进行空实现,然后再继承这个抽象类,就不需要实现其它不用的方法,这就是钩子方法的作用。
单词排序显示案例
统计英文文本文件中单词的步骤:
①标题读取文件的内容。
②标题统计出文件内容中的全部单词。
③标题将单词按着某种顺序排序,比如,按字典顺序或单词的长度排序单词,但允许具体模板对排序挂钩,即具体模板可以对单词排序也可以不对单词进行排序。
④标题输出全部的单词。
抽象模板
WordsTemplate.java
package mbffms_2;
import java.io.*;
public abstract class {
File file;
String content;
String[] word;
WordsTemplate(File file){
this.file=file;
content="";
}
public final void showAllWords() {//模板方法
readContent();
getWords();
if(isSort()) //挂钩处
sort(word);
printWords(word);
}
public void readContent() {
try {
StringBuffer str=new StringBuffer();
FileReader inOne=new FileReader(file);
BufferedReader inTwo=new BufferedReader(inOne);
String s=null;
while((s=inTwo.readLine())!=null)
str.append(s+"\n");
content=new String(str);
inOne.close();
inTwo.close();
}
catch(IOException exp) {}
}
public final void getWords() {
//空格字符、数字和符号组成的正则表达式
String regex="[\\s\\d\\p{Punct}]+";
word=content.split(regex);
}
public boolean isSort() {//钩子方法
return true;
}
public void sort(String[] word) {} //钩子方法
public final void printWords(String[] word) {
int j=0;
for(int i=0;i<word.length;i++) {
System.out.printf("%-10s",word[i]);
//每7个单词换一行输出
j++;
if(j>6) {
System.out.println();
j=0;
}
}
System.out.println();
}
}
具体模板
WordSortTemplate.java
package mbffms_2;
import java.io.*;
import java.util.*;
public class WordSortTemplate extends WordsTemplate{
WordSortTemplate(File file) {
super(file);
}
public void sort(String[] word) {
Arrays.sort(word);
}
}
WordNoSortTemplate.java
package mbffms_2;
import java.io.*;
import java.util.*;
public class WordNoSortTemplate extends WordsTemplate{
WordNoSortTemplate(File file) {
super(file);
}
public boolean isSort() {
return false;
}
}
测试类
package mbffms_2;
import java.io.File;
public class test {
public static void main(String[] args) {
//注意文件存放的位置,位于java项目文件夹中
File file=new File("test.txt");
WordsTemplate template=new WordSortTemplate(file);
//按字典顺序大写字母在小写字母之前
System.out.println(file.getName()+"中有如下的单词(按字典顺序):");
template.showAllWords();
template=new WordNoSortTemplate(file);
System.out.println(file.getName()+"中有如下的单词(按文中出现的先后顺序):");
template.showAllWords();
}
}