模板方法模式:

由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。

泡咖啡和泡茶的例子

     var Coffee = function(){};    //作为构造函数
Coffee.prototype.boilWater = function(){
console.log( '把水煮沸' );
};
Coffee.prototype.brewCoffeeGriends = function(){
console.log( '用沸水冲泡咖啡' );
};
Coffee.prototype.pourInCup = function(){
console.log( '把咖啡倒进杯子' );
};
Coffee.prototype.addSugarAndMilk = function(){
console.log( '加糖和牛奶' );
}; Coffee.prototype.init = function(){
this.boilWater(); //煮水
this.brewCoffeeGriends(); //泡咖啡
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 drink=function(){}  //作为抽象的构造类
drink.prototype.boilWater=function(){
console.log( '把水煮沸' );
}
drink.prototype.brew=function(){}; //空方法,用来给模板套用
drink.prototype.pourInCup = function(){}; // 同上
drink.prototype.addCondiments = function(){}; // 同上 drink.prototype.init = function(){ //模板在这里,重复的事情放在模板里
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
};

然后就是具体的咖啡类和茶类

     /**创建咖啡类**/
var Coffee = function(){}; //这是一个具体的类,作为构造函数存在
Coffee.prototype = new drink(); //把构造函数的prototype指向抽象类的实例 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 drink(); //把构造函数的prototype指向抽象类的实例 Tea.prototype.brew = function(){
console.log( '用沸水浸泡茶叶' );
};
Tea.prototype.pourInCup = function(){
console.log( '把茶倒进杯子' );
};
Tea.prototype.addCondiments = function(){
console.log( '加柠檬' );
}; var tea = new Tea(); //新建茶实例
tea.init(); //调用模板
/*结果*/
//把水煮沸
//用沸水浸泡茶叶
//把茶倒进杯子
//加柠檬

使用es6的话,代码可以简洁不少

      class drink{    //抽象模板父类
boilWater(){
console.log("把水煮沸");
};
brew(){};
pourInCup(){};
addCondiments(){}; init(){
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
}
} class Coffee extends drink{ //具体的类,内部重写相应方法
brew(){
console.log("用沸水冲泡咖啡");
}
pourInCup(){
console.log( '把咖啡倒进杯子' );
}
addCondiments(){
console.log( '加糖和牛奶' );
}
} var coffee=new Coffee(); //实例
coffee.init(); //把水煮沸
//用沸水冲泡咖啡
//把咖啡倒进杯子
//加糖和牛奶

js实现模板模式的一些问题

我们在抽象父类中提供了模板,在具体的类中重写相应的方法,但是这个过程全靠程序员的自觉和记忆,语言层面并没有提供任何检查,如果我们忘了重写相应的方法,js也不会报错。
一种解决方案是用鸭子类型来模拟接口检查,缺点就是会带来很多不必要的复杂性,增加很多和业务无关的代码。
另一种解决方案是抽象父类中的相应抽象方法里都抛出错误,如果子类没有重写相应方法,运行时就会报错,如下:

     drink.prototype.brew=function(){
throw new Error( '子类必须重写brew 方法' );
};

钩子方法

可以增加自由度,有的子类并不适合把模板方法全部运行,钩子方法可以让子类自行决定是否执行对应的模板方法。

     drink.prototype.add=function(){  //钩子方法,子类中可以改写,模板方法中会进行判断
return true; //默认为true,用于判断
}
drink.prototype.init = function(){ //模板方法
this.boilWater();
this.brew();
this.pourInCup();
if( this.add() ){ //如果挂钩返回true,则需要调料
this.addCondiments();
}
};

javascript设计模式与开发实践阅读笔记(11)—— 模板方法模式的更多相关文章

  1. javascript设计模式与开发实践阅读笔记(4)——单例模式

    定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...

  2. javascript设计模式与开发实践阅读笔记(8)——观察者模式

    发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...

  3. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  4. javascript设计模式与开发实践阅读笔记(6)——代理模式

    代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...

  5. javascript设计模式与开发实践阅读笔记(5)——策略模式

    策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...

  6. javascript设计模式与开发实践阅读笔记(9)——命令模式

    命令模式:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计软件,使得请求发送者和请求接收者能够消除彼此之间的耦合关系. 说法很复 ...

  7. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  8. 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式

    第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...

  9. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

随机推荐

  1. hibernate--多对多双向关联(少用)

    老师知道自己教了哪些学生, 学生也知道教自己的有哪些老师. Teacher.java: package com.bjsxt.hibernate; import java.util.HashSet; i ...

  2. LAMP优化

    LAMP系统优化是非常必要的,一个好的优化能使系统运作的越快,从而提高工作效率,下面我将从几方面给大家详细介绍下LAMP系统优化的内容. 一.硬件优化 1.升级硬件的一般规则:对于 PHP 脚本而言, ...

  3. OPENCV形态学操作1

    形态学操作是指基于形状的一系列图像处理操作,包括膨胀,腐蚀,二值化,开运算,闭运算,顶帽算法,黑帽算法,形态学梯度等,最基本的形态学操作就是膨胀和腐蚀. 一.膨胀 首先需要明确一个概念,膨胀和腐蚀都是 ...

  4. LPC2478的硬件IIC使用

    LPC2478的IIC使用 LPC2478带有三个IIC接口,每个IIC都可以工作在主机或者从机模式下,LPC的IIC的架构是一种状态机的形式,在不同的的时间做不同的工作之后有不同的状态来表示, 简单 ...

  5. 为什么建立TCP连接需要三次握手,为什么断开TCP连接需要四次握手,TIME_WAIT状态的意义

    为什么建立TCP连接需要三次握手? 原因:为了应对网络中存在的延迟的重复数组的问题 例子: 假设client发起连接的连接请求报文段在网络中没有丢失,而是在某个网络节点长时间滞留了,导致延迟到达ser ...

  6. Swing 窗口的最小化到系统图标与还原

    2014年2月26日 13:01:47 一个上午的功夫,终于折腾好了. 上午主要是卡在监听事件的参数问题.当时脑子不好使,忘记事件是自己构造的,傻傻的测试了半天,如何传递窗口的参数 等中午解决的时候, ...

  7. Docker学习计划

    刚开始学习Docker的时候,找资料在网上看到最多的是Docker的好处.比如: 1.Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多 2.Docker 对系统资源的利用率很高, ...

  8. React Native 之 搭建开发环境

    现在只能在MAC系统上安装. 1. 首先,HomeBrew 这是一个包管理库,用来下载其它工具. 打开网站:brew.sh 网页有个命令 /usr/bin/ruby -e "$(curl - ...

  9. webgl 网站demo

    网络上的一些经典的WebGL资源网站和WebGL开源引擎整理 http://www.babylonjs.com/ http://threejs.org/ http://www.finalmesh.co ...

  10. windy数(bzoj 1227)

    Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? In ...