模板方法模式是一种只需使用继承就可以实现的非常简单的模式。
模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体实现子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
假如有一些平行的子类,各个子类间有些相同的行为,也有不同的行为。如果相同与不同的行为都混合在各个子类的实现中,说明相同的行为会在各个子类中重复出现。但实际上,相同的行为可以被搬移到另一个单一的地方,模板方法模式就是为解决这类问题而出现的。相同的行为被提到了父类中,不同的行为保留在各个子类中。这也很好地体现了泛华的思想。
例如,泡茶和冲咖啡的过程经过提炼,得到以下4个步骤:
1.把水煮沸
2.用沸水冲泡饮料
3.把饮料倒进杯子
4.加调料
代码如下:
var Beverage = function(){};
Beverage.prototype.boilWater = function(){
console.log("把水煮沸");
}
Beverage.prototype.brew = function(){}; //冲泡饮料
Beverage.prototype.pourInCup = function(){}; //倒入杯子
Beverage.prototype.addCondiments function(){}; // 加调料
Beverage.prototype.init = function(){
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
}
//咖啡
var Coffee = function(){};
Coffee.prototype = new Beverage();
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 Beverage();
Tea.prototype.brew = function(){
console.log("用沸水浸泡茶叶");
}
Tea.prototype.pourInCup = function(){
console.log("把茶倒进杯子");
}
Tea.prototype.addCondiments = function(){
console.log("加柠檬");
}
var tea = new Tea();
tea.init();
在上面的例子中,模板方法是Beverage.prototype.init。它里面封装了算法框架,可以指导子类以何种顺序去执行哪些方法。
再看下面代码,不需要继承也可以达到和继承一样的效果。
var Beverage = function(param){
var boilWater = function(){
console.log("把水煮沸");
};
var brew = param.brew || function(){
throw new Error("必须传递brew方法");
};
var pourInCup = param.pourInCup || function(){
throw new Error("必须传递pourInCup方法");
};
var addCondiments = param.addCondiments || function(){
throw new Error("必须传递addCondiments方法");
};
var F = function(){};
F.prototype.init = function(){
boilWater();
brew();
pourInCup();
addCondiments();
};
return F;
}
var Coffee = Beverage({
brew: function(){
console.log("用沸水冲泡咖啡");
},
pourInCup: function(){
console.log("把咖啡倒进杯子");
},
addCondiments: function(){
console.log("加糖和牛奶");
}
});
var Tea = Beverage({
brew: function(){
console.log("用沸水浸泡茶叶");
},
pourInCup: function(){
console.log("把茶倒进杯子");
},
addCondiments: function(){
console.log("加柠檬");
}
});
var coffee = new Coffee();
coffee.init();
var tea = new Tea();
tea.init();
在这段代码中,把方法brew、pourInCup、addCondiments这些方法一次传入Beverage函数,Beverage函数被调用后返回构造器F。F类中包含了模板方法F.prototype.init。跟继承得到的效果一样。
模板方法模式是一种典型的通过封装变化提高系统扩展性的设计模式。