定义:只需使用原型链继承就可以实现简单的模式
组成:由抽象的父类和具体实现的子类组成。抽象父类封装子类的算法框架,公共方法和封装子类中所有方法的执行顺序方法。子类通过继承抽象类,可以重写父类方法
应用场景:模板方法模式常用于搭建项目的框架,定好框架的骨架,然后继承框架的结构之后,往里面添加功能;
web开发中,搭建一系列的UI组件,组件的构建过程:
1)初始化一个div容器
2)通过ajax请求拉取到相应的数据
3)把数据渲染到div容器里面,完成组件构造
4)通知用户组件渲染完毕
1)、4)相同,子类只需要重写2)、3)
模板方法模式中的钩子方法:用于解决一些特例,隔离变化。在父类中容易发生变化的地方放置钩子,钩子有一个默认的实现,由子类决定要不要挂钩。钩子方法的返回结果决定模板方法后面的执行步骤
茶与咖啡例子
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<script src="jquery-3.1.1.min.js"></script>
</head>
<body>
<button id='btn'>execute command</button>
<script>
/**********抽象父类,泡一杯饮料的整个过程*********/
let Beverage = function(){};
//下面3个空方法,由子类重写,父类提供接口
Beverage.prototype.boilWater = function(){
console.log('把水煮沸');
};
// 防止子类没有重写这些方法带来的错误
Beverage.prototype.brew = function(){
throw new Error('子类必须重写brew');
};
Beverage.prototype.pourInCup = function(){
throw new Error('子类必须重写pourInCup');
};
Beverage.prototype.addCondiments = function(){
throw new Error('子类必须重写addCondiments');
};
// 钩子方法,true-表示挂钩,false-表示不挂钩,默认为true
Beverage.prototype.customerWantsCondiments = function(){
return true;
};
//这个就是模板方法,封装子类的算法框架,指导子类以何种顺序执行哪些方法
Beverage.prototype.init = function(){
this.boilWater();
this.brew();
this.pourInCup();
// 这里需要判断钩子方法的返回值,做下一步的处理
if( this.customerWantsCondiments() ){ //挂钩返回true,表示加饮料
this.addCondiments();
}
};
/*******创建子类Coffee,继承父类,并且重写父类中的方法********/
let CoffeeWithHook = function(){};
// 通过原型链继承父类
CoffeeWithHook.prototype = new Beverage();
// 重写父类中的方法
CoffeeWithHook.prototype.brew = function(){
console.log('用沸水冲泡咖啡');
};
CoffeeWithHook.prototype.pourInCup = function(){
console.log('把咖啡倒进杯子');
};
CoffeeWithHook.prototype.addCondiments = function(){
console.log('加糖和牛奶');
};
// 重写父类中的钩子函数
CoffeeWithHook.prototype.customerWantsCondiments = function(){
return window.confirm('咖啡中需要添加饮料吗?');
};
/*********创建子类Tea,继承父类,并且重写父类中的方法************/
let TeaWithHook = function(){};
// 通过原型链继承父类
TeaWithHook.prototype = new Beverage();
// 重写父类中的方法
TeaWithHook.prototype.brew = function(){
console.log('用沸水浸泡茶叶');
};
TeaWithHook.prototype.pourInCup = function(){
console.log('把茶倒进杯子');
};
TeaWithHook.prototype.addCondiments = function(){
console.log('加柠檬');
};
// 重写父类中的钩子函数
TeaWithHook.prototype.customerWantsCondiments = function(){
return window.confirm('茶中需要添加饮料吗?');
};
/******创建Tea和Coffee实例对象********/
let coffee = new CoffeeWithHook(),
tea = new TeaWithHook();
coffee.init();
tea.init();
</script>
</body>
</html>