模板方法(Template Method)
模板方法模式是一种只需要继承就可以实现的非常简单的模式。
模板方法模式通常由两部分组成:
- 抽象父类
- 实现具体方法的子类
通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。
子类通过继承父类,也继承了整个算法结构,并且需要重写父类的方法,来实现具体的业务逻辑。
典型案例 Coffee or Tea
泡一杯咖啡的步骤:
(1)把水煮沸
(2)用沸水冲泡咖啡
(3)把咖啡倒进杯子
(4)加奶和糖
泡一杯茶的步骤:
(1)把水煮沸
(2)用沸水浸泡茶叶
(3)把茶水倒进杯子
(4)加柠檬
var Coffee = function () { };
Coffee.prototype.boilWater = function () {
console.log('把水煮沸');
};
Coffee.prototype.brewCoffeeGrounds = function () {
console.log('用水冲泡咖啡');
};
Coffee.prototype.pourInCup = function () {
console.log('把咖啡倒进杯子');
};
Coffee.prototype.addSugarAndMilk = function () {
console.log('加糖和奶');
};
Coffee.prototype.init = function () {
this.boilWater();
this.brewCoffeeGrounds();
this.pourInCup();
this.addSugarAndMilk();
};
var coffee = new Coffee();
coffee.init();
var Tea = function () {};
Tea.prototype.boilWater = function () {
console.log('把水煮沸');
};
Tea.prototype.steepTeaBag = function () {
console.log('用水浸泡茶叶');
};
Tea.prototype.pourInCup = function () {
console.log('把茶水倒进杯子');
};
Tea.prototype.addLemon = function () {
console.log('加柠檬');
};
Tea.prototype.init = function () {
this.boilWater();
this.steepTeaBag();
this.pourInCup();
this.addLemon();
};
var tea = new Tea();
tea.init();
使用模板方法模式重构上面代码:
var Baverage = function () {
};
Baverage.prototype.boilWater = function () {
console.log('把水煮沸');
};
Baverage.prototype.brew = function () {
// 空方法,留着给子类重写
// 为了检查子类是否重写了该方法,抛出一个异常
throw new Error('子类必须重写brew方法');
};
Baverage.prototype.pourInCup = function () {
// 空方法,留着给子类重写
throw new Error('子类必须重写pourInCup方法');
};
Baverage.prototype.addCondiments = function () {
// 空方法,留着给子类重写
throw new Error('子类必须重写addCondiments方法');
};
Baverage.prototype.init = function () {
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
};
// 创建子类
var Coffee = function(){};
// 继承父类
Coffee.prototype = new Baverage();
// 重写父类的方法
Coffee.prototype.brew = function () {
console.log('用沸水冲泡咖啡');
};
Coffee.prototype.pourInCup = function () {
console.log('把咖啡倒进杯子');
};
Coffee.prototype.addCondiments = function () {
console.log('加糖和牛奶');
};
var coffee = new Coffee();
coffee.init();
var Tea = function () {};
Tea.prototype = new Baverage();
Tea.prototype.brew = function () {
console.log('用水浸泡茶叶');
};
Tea.prototype.pourInCup = function () {
console.log('把茶水倒进杯子');
};
Tea.prototype.addCondiments = function () {
console.log('加柠檬');
};
var tea = new Tea();
tea.init();
Baverage构造函数,特别像Java中的抽象类。
但JavaScript中并没有从语法层面提供对抽象类的支持。如果子类没有重写父类的方法,编译器也不会报错。最终执行时,请求会沿着原型链执行到父类的方法,所以不会报错。为了保证子类重写父类的方法,所以在父类方法中直接throw了Exception。
对于JavaScript来说,也可以不使用继承来完成以上的效果。
还可以使用高阶函数来实现,这也是很多常用组件实现的方式:
var Baverage = function (options) {
var boilWater = function () {
console.log('把水煮沸');
};
var brew = options.brew || function(){
throw new Error('必须传入brew方法');
};
var pourInCup = options.pourInCup || function(){
throw new Error('必须传入pourInCup方法');
};
var addCondiments = options.addCondiments || function(){
throw new Error('必须传入addCondiments方法');
};
var F= function(){};
F.prototype.init = function(){
boilWater();
brew();
pourInCup();
addCondiments();
};
return F;
};
// 创建子类
var Coffee = Baverage({
brew : function () {
console.log('用沸水冲泡咖啡');
},
pourInCup : function () {
console.log('把咖啡倒进杯子');
},
addCondiments : function () {
console.log('加糖和牛奶');
},
});
var coffee = new Coffee();
coffee.init();
var Tea = Baverage({
brew : function () {
console.log('用水浸泡茶叶');
},
pourInCup : function () {
console.log('把茶水倒进杯子');
},
addCondiments : function () {
console.log('加柠檬');
},
});
var tea = new Tea();
tea.init();
网友评论