模板方法模式是一种行为设计模式,它是需要通过继承实现的设计模式.

模板方法模式有两个部分组成.

  1. 抽象父类.它定义了算法操作框架和具体的算法执行流程.(一般在父类定义 init 方法作执行算法)
  2. 具体实现抽象父类的子类. 子类实现了父类定义的算法结构,但最后的执行通过父类实现的方法执行.

注意: 父类只负责定义算法框架,具体实现有子类完成.不同的子类,实现抽象类定义的抽象方法可以不同,但子类不应该改变算法的执行步骤!

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
var Beverage = function (){};

Beverage.prototype.boilwater = function () {
console.log('把水煮开');
}

Beverage.prototype.brew = function () {
console.log('子类必须重写 brew 方法')
}

Beverage.prototype.pourInCup = function () {
console.log('子类必须重写 pourInCup方法');
}

Beverage.prototype.addCondiments = function () {
console.log('子类必须重写 addCondiments 方法');
}

Beverage.prototype.customerWantsCondiments = function () {
return true; // 是否需要调料
}

Beverage.prototype.init = function () {
this.boilwater();
this.brew();
this.pourInCup();
// 在执行算法过程中,可能需要做判断处理
// 这时 我们可以在父类方法给子类留出钩子方法 做判断处理用
if(this.customerWantsCondiments()) {
this.addCondiments();
}
}

var CoffeeWithHook = function () {};

CoffeeWithHook.prototype.brew = function () {
console.log('用沸水冲泡咖啡')
}

CoffeeWithHook.prototype.pourInCup = function () {
console.log('把咖啡倒进杯子');
}
CoffeeWithHook.prototype.addCondiments = function () {
console.log('加糖和牛奶');
}
CoffeeWithHook.prototype.customerWantsCondiments = function () {
retunr window.confirm('请问需要调料吗?')
}
var coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.init();

使用场景

模板方法模式是一种典型的通过封装变化提高系统扩展性的设计模式.它适用于面向对象开发语言,供架构师搭建项目的框架,架构师定好框架的骨架,程序员继承框架的结构后,负责往里面填空.

在JavaScript中,因为一般通过高阶函数代替纯粹的面向对象继承的模板方法模式.利用高阶函数实现的模板方法模式被称为好莱坞模式.

好莱坞模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var Beverage = function (param) {
var boilWater = ()=> {
console.log('把水煮开');
}
var brew = param.brew || () => {
throw new Error('必须传递brew方法');
}
var pourInCup = param.pourInCup || () => {
throw new Error('必须传递pourInCup方法');
}
var addCondiments = param.addCondiments || () => {
throw new Error('必须传递 addCondiments 方法');
}
var F = () =>{};
F.prototype.init = function () {
boilWater();
brew();
pourInCup();
addCondiments();
}
return F;
}

var Coffer = Beverage({
brew () {
console.log('用沸水冲泡咖啡☕️')
},
pourInCup() {
console.log('把咖啡倒进杯子')
},
addCondiments() {
console.log('加糖和牛奶');
}
});

var Tea = Beverage({
brew () {
console.log('用沸水浸泡茶叶🍵')
},
pourInCup() {
console.log('把茶倒进杯子')
},
addCondiments() {
console.log('加柠檬🍋');
}
});

var coffee = new Coffee();
coffee.init();

var tea = new Tea();
tea.init();