javascript设计模式与开发实践阅读笔记(11)—— 模板方法模式
模板方法模式:
由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
泡咖啡和泡茶的例子
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)—— 模板方法模式的更多相关文章
- javascript设计模式与开发实践阅读笔记(4)——单例模式
定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...
- javascript设计模式与开发实践阅读笔记(8)——观察者模式
发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...
- javascript设计模式与开发实践阅读笔记(7)——迭代器模式
迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...
- javascript设计模式与开发实践阅读笔记(6)——代理模式
代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...
- javascript设计模式与开发实践阅读笔记(5)——策略模式
策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...
- javascript设计模式与开发实践阅读笔记(9)——命令模式
命令模式:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计软件,使得请求发送者和请求接收者能够消除彼此之间的耦合关系. 说法很复 ...
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)
说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...
- 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式
第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)
上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...
随机推荐
- Pop框架简述
Facebook发布了Paper之后,进一步开源了其背后的动画引擎Pop,此框架并不满足于苹果自身的动画单调性,致力于给用户一种逼真的动画效果,可以减少用户对于苹果原生Core Animation 复 ...
- 基于LNMP的Zabbbix之PHP源码安装
安装一些依赖的包 wget -c ftp://xmlsoft.org/libxml2/libxml2-2.7.8.tar.gz .tar.gz -C ../source/ cd ../source/l ...
- 自己动手编译octave 4.0.0
今天在做作业的时候,发现imread不能使用,说要安装相应的图形包,可是要安装image时,却发现要求4.0.0版本,而我本机的linux系统ubuntu15.04只有3.8.x的安装源,没办法,只能 ...
- 单应性(homography)变换的推导
矩阵的一个重要作用是将空间中的点变换到另一个空间中.这个作用在国内的<线性代数>教学中基本没有介绍.要能形像地理解这一作用,比较直观的方法就是图像变换,图像变换的方法很多,单应性变换是其中 ...
- mysql 不同语法
http://blog.csdn.net/kesaihao862/article/details/6718443 REPLACE INTO id_28_repayid(stub) VALUES(1); ...
- iOS开发——获取本设备IP
不说废话,直接上代码. #import <ifaddrs.h> #import <arpa/inet.h> - (NSString *)getIPAddress { NSStr ...
- Instruments使用实战
http://www.cocoachina.com/ios/20150225/11163.html 最近采用Instruments 来分析整个应用程序的性能.发现很多有意思的点,以及性能优化和一些分析 ...
- angular中的$http配置和参数
依赖:$httpBackend $cacheFactory $rootScope $q $injector 使用:$http(config); 参数: method:字符串,请求方法. url:字符串 ...
- iOS 改变导航栏高度
需求: appdelegate里 rootviewcontroller 是tabbarcontroller,tabbarcontroller里有4个navigationcontroller,改变每个n ...
- UVa 10925 - Krakovia
题目大意:关于大数的加法和除法的,用Java的BigInteger可以方便地解决. import java.io.*; import java.util.*; import java.math.*; ...