模板方法模式是一种只需使用继承就可以实现的非常简单的模式。模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。通常在抽象父类中封装了子类的算法框架,也包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
模板方法模式包含以下角色:
定义 AbstractClass 抽象类
class AbstractClass {
public method1(): void {
throw new Error("Abstract Method");
}
public method2(): void {
throw new Error("Abstract Method");
}
public method3(): void {
throw new Error("Abstract Method");
}
public templateMethod(): void {
console.log("templateMethod is being called");
this.method1();
this.method2();
this.method3();
}
}
定义 ConcreteClass 类
class ConcreteClass extends AbstractClass {
public method1(): void {
console.log("method1 of ConcreteClass");
}
public method2(): void {
console.log("method2 of ConcreteClass");
}
public method3(): void {
console.log("method3 of ConcreteClass");
}
}
function show(): void {
const cc: ConcreteClass = new ConcreteClass();
cc.templateMethod();
}
以上代码成功运行后会输出以下结果:
templateMethod is being called
method1 of ConcreteClass
method2 of ConcreteClass
method3 of ConcreteClass
下面为了让小伙伴们能更好地理解模板方法设计模式,我们来以 “泡咖啡与泡茶” 这个经典的例子来深入介绍模板方法。
首先,我们先来泡一杯咖啡,泡咖啡的步骤通常如下:
接下来,开始准备我们的茶,泡茶的步骤跟泡咖啡的步骤类似:
根据上面泡咖啡和泡茶的步骤,我们可以整理出以下表格:
泡咖啡步骤 | 泡茶步骤 |
---|---|
把水煮沸 | 把水煮沸 |
用沸水冲泡咖啡 | 用沸水浸泡茶叶 |
把咖啡倒进杯子 | 把茶水倒进杯子 |
加糖和牛奶 | 加柠檬 |
我们可以发现泡咖啡和泡茶主要有以下不同点:
经过抽象之后,不管是泡咖啡还是泡茶,我们都能整理为下面四步:
所以,不管是冲泡还是浸泡,我们都能给它一个新的方法名称,比如说 brew()
。同理,不管是加糖和牛奶,还是加柠檬,我们都可以称之为 addCondiments()
。
现在我们可以创建一个抽象父类来表示泡一杯饮料的整个过程。无论是咖啡(Coffee),还是茶(Tea),都被我们用饮料(Beverage)来表示,最后我们来看一下具体实现。
创建 Beverage 抽象类
abstract class Beverage {
boilWater() {
console.log("把水煮沸");
}
abstract brew(): void;
abstract pourInCup(): void;
abstract addCondiments(): void;
// 模板方法
makeBeverage() {
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
}
}
创建 Coffee 类
class Coffee extends Beverage {
brew(): void {
console.log("用沸水冲泡咖啡");
}
pourInCup(): void {
console.log("把咖啡倒进杯子");
}
addCondiments(): void {
console.log("加糖和牛奶");
}
}
创建 Tea 类
class Tea extends Beverage {
brew(): void {
console.log("用沸水浸泡茶叶");
}
pourInCup(): void {
console.log("把茶倒进杯子");
}
addCondiments(): void {
console.log("加柠檬");
}
}
使用示例
function show(): void {
const coffee: Coffee = new Coffee();
const tea: Tea = new Tea();
coffee.makeBeverage();
tea.makeBeverage();
}
以上代码成功运行后会输出以下结果:
把水煮沸
用沸水冲泡咖啡
把咖啡倒进杯子
加糖和牛奶
把水煮沸
用沸水浸泡茶叶
把茶倒进杯子
加柠檬
在模板方法设计模式中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。模板方法定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。