一、描述
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
1.抽象模板类:负责定义算法方法
2.具体模板类:实现抽象模板类方法
类图:
二、优点
1.封装不变部分,扩展可变部分
2.提取公共代码,便于维护
3.行为由父类控制,子类实现
三、缺点
1.每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
2.修改困难。当父类添加一个抽象方法时,所有子类都要同步修改,增加了复杂性。
四、适用场景
适用于某种行为的算法。区别于创建型模式的目的,创建型模式中的工厂方法、建造者模式都是为了创造产品。而模板方法的最终目的并不是创造产品,而是执行每个步骤的算法,它的关注点在于算法。在研究模板方法时,对于建造者模式、策略模式与模板方法的区别和用法有点儿懵逼了,查了很多资料之后,终于弄清三者区别:
建造者模式 | 模板方式 | 策略模式 | |
所属 | 创建者模式 | 行为模式 | 行为模式 |
定义 | 是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象 | 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 | 定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。 |
目的 | 创造出产品 | 完成某个功能,最终效果不一定相同。 | 完成某个功能,最终的效果是相同的。 |
行为 | 通过一系列流程创造出不同产品,流程相同,但是每个步骤细节不同。 | 某个事件的流程相同,每个步骤可以有不同算法,相同步骤的不同算法不可以相互替换。 | 同一个功能,但是具体算法可以不同,并且不同算法可以相互替换。 |
相同点 |
建造者和模板方法模式都是有流程; 模板方法和策略模式都是有算法。 |
五、示例
现有的jdk中,读取文件流抽象类InputStream中有read方法,其子类FileInputStream和BufferedInputStream分别实现了read方法,其中FileInputStream用于读取文件,BufferedInputStream用于读取数据流。
类图如下:
源码就不展示出来了,直接上示例。
2.读取流
public class Client {
public static void main(String[] args) {
String path = "src/test/resources/txt.txt";
File file = new File(path);
//1.读取文件
readFile(file);
//2.读取流
try {
FileInputStream inputStream = new FileInputStream(file);
readInputStream(inputStream);
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取文件
*/
public static void readFile(File file) {
try {
System.out.println("直接读取文件到内存");
//用于读取文件File
FileInputStream inputStream = new FileInputStream(file);
int a;
while ((a = inputStream.read()) != -1) {
System.out.print((char) a);
}
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取文件流
*/
public static void readInputStream(InputStream inputStream) {
try {
System.out.println("加了缓冲,从缓存到内存");
//用于读取流inputStream
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
int a;
while ((a = bufferedInputStream.read()) != -1) {
System.out.print((char) a);
}
bufferedInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.效果