模板模式
一、动机
在面向对象的设计中,有很多类似的算法或任务需要完成,但这些算法或任务的具体实现方式可能会存在差异。使用继承来实现这些算法或任务,会导致代码重复和维护困难。因此,模板模式应运而生,该模式通过定义一个模板方法,并将具体实现放到子类当中,使得算法框架与具体实现分离,并且具体实现可以方便地替换。
二、概念与原理
概念:
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,模板方法模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤,这种类型的设计模式属于行为型模式。
图1:原理类图
三、应用场景
处理顺序固定的一系列操作,例如算法的执行步骤或者工作流程;
在不同的情境下,需要完成类似的任务,但是细节有所不同的场景;
通过一种标准化的方式,让子类实现算法的某些步骤,强制子类实现该算法,例如常见的Java Servlet。
四、角色
抽象类(AbstractClass):声明并定义了抽象模板方法,包含了算法执行的骨架流程;
具体类(ConcreteClass):实现了抽象类中的抽象模板方法,完成了算法的具体实现。
五、实现代码
以制作咖啡和茶为例:
// 抽象类
public abstract class CaffeineBeverage {
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
public void boilWater() {
System.out.println("Boiling water");
}
public abstract void brew();
public void pourInCup() {
System.out.println("Pouring into cup");
}
public abstract void addCondiments();
// 钩子方法,由子类进行覆盖
public boolean customerWantsCondiments() {
return true;
}
}
// 具体类,制作咖啡
public class Coffee extends CaffeineBeverage {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
public boolean customerWantsCondiments() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.print("Would you like milk and sugar with your coffee (y/n)? ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
// 具体类,制作茶
public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("Steeping the tea");
}
public void addCondiments() {
System.out.println("Adding Lemon");
}
}
六、优缺点
优点:
封装不变部分,扩展可变部分,使得代码复用性高;
模板模式是一种代码骨架,可以避免重复的代码;
通过抽象类定义算法流程,保证了算法的正确性。
缺点:
模板模式很难同时满足“封装变化”和“具体实现共享”的要求,需要根据实际情况进行权衡;对于需要频繁修改算法流程的场景,使用模板模式会带来额外的维护工作。
总之,模板模式适用于具有类似算法或任务,但是实现细节略有差异的场景。通过将算法框架与具体实现分离,使得代码复用性高,并且可以方便地进行扩展和维护。