最近看了一本《Javascript设计模式与开发实践》;这本书写的很不错,书中举的例子也很通俗易懂。一早就想抽点时间写写的从中的感悟,好像也拖了好久了,什么课程设计呀,考试啦。今天终于静下来了。
首先我们来谈谈满大街都是的-单例模式:
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式虽然简单,但是在javascript这种弱类型的语言中却又着举足轻重的地位;它可以减少命名空间污染。尤其在大型的项目。十分重要。
var A={};//如果对象a是独一无二的,我们就定义了一个单例对象
A.sum=function(a,b){
return a+b;
}
A.multiply=function(a,b){
return a*b;
}
......
惰性单例:惰性单例指的是在需要的时候才创建对象实例。惰性单例是单例模式的重点,这种技术在实
际开发中非常有用,有用的程度可能超出了我们的想象。
Single.getInstance=(function(){
var instance=null;
return function(name){
if(!instance){
instance=new Single(name);
}
}
return instance;
})();
//来一个具体的例子,生成一个遮幕,这是我们在开发中经常会遇到的。
var createDiv=(function(){
var div;
return function(){
div=document.createElement("div");
div.style.width="100%";
div.style.height="100%";
div.style.zIndex="999";
docment.body.appendChild(div);
}
return div;
})();
通用的惰性单例:
var getSingle = function( fn ){
var result;
return function(){
return result || ( result = fn .apply(this, arguments ) );
}
};
现在我们来说说策略模式:
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
现在有一个问题是:根据用户的等级,返回用户每个月可领取的代金券数量。
var getVoucher=function(level){
if(level=="H"){
return 5;
}
if(level=="M"){
return 3;
}
if(level=="L"){
return 1;
}
}
可以发现,这段代码十分简单,但是存在着显而易见的缺点。
- getVoucher函数比较庞大,包含了很多if-else 语句,这些语句需要覆盖所有的逻辑分支
- getVoucher 函数缺乏弹性,如果增加了一种新等级HH,那我们必须深入getVoucher 函数的内部实现,这是违反开放-封闭原则的。
- 算法的复用性差,如果在程序的其他地方需要重用用户每个月可领取的代金券数量?我们的选择只有复制和粘贴。
使用策略模式重构代码
//策略类
var levelH=function(){};
levelH.prototype.count=function(){
return 5;
}
var levelM=function(){};
levelM.prototype.count=function(){
return 3;
}
var levelL=function(){};
levelL.prototype.count=function(){
return 1;
}
//
var personLevel=function(){
this.level=null;//原始等级
}
personLevel.prototype.setLevel=function(level){
this.level=level;//设置等级
}
personLevel.prototype.setCount=function(count){//设置策略类
this.count=count;
}
personLevel.prototype.getCount=function(){//获取代金券数量
return this.count.count(this.level)
}
JavaScript 版本的策略模式
var level={
"H":function(){
return 5;
},
"M":function(){
return 5;
},
"L":function(){
return 1;
}
}
//
var personCount=function(level){
return level[level]();
}
console.log(personCount('H'));//输出5;
1.策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
2.策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的strategy 中,使得它们易于切换,易于理解,3.易于扩展。
4.策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
5.在策略模式中利用组合和委托来让Context 拥有执行算法的能力,这也是继承的一种更轻便的替代方案。
当然,策略模式也有一些缺点,但这些缺点并不严重。
首先,使用策略模式会在程序中增加许多策略类或者策略对象。其次,要使用策略模式,必须了解所有的策略类。
最后我们来聊聊代理模式:
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理分为:保护代理,虚拟代理,远程代理,缓存代理等等。
保护代理用于控制不同权限的对象对目标对象的访问,但在JavaScript 并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,下面我们主要说虚拟代理。
虚拟代理实现图片预加载:
在Web 开发中,图片预加载是一种常用的技术,如果直接给某个img 标签节点设置src 属性,
由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张
loading 图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img 节点里,这种
场景就很适合使用虚拟代理。
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ){
imgNode.src = src;
}
}
})();
myImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );
我们把网速调至5KB/s,然后通过MyImage.setSrc 给该img 节点设置src,可以看到,在图片被加载好之前,页面中有一段长长的空白时间。现在开始引入代理对象proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的菊花图loading.gif, 来提示用户图片正在加载。代码如下:
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ){
imgNode.src = src;
}
}
})();
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage.setSrc( this.src );
}
return {
setSrc: function( src ){
myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
img.src = src;
}
}
})();
缓存代理用于ajax异步请求数据
我们在常常在项目中遇到分页的需求,同一页的数据理论上只需要去后台拉取一次,这些已经拉取到的数据在某个地方被缓存之后,下次再请求同一页的时候,便可以直接使用之前的数据。
一个网页中有4个tab标签,每切换一个就从后台抓取相对性的数据显示到content中。用缓存代理的话,每个tab只需要从后台抓取一次数据,减少请求。
//缓存代理去保存数据
var proxyAjaxData=(function(){
var cache={};
return function(obj){//传入参数
if(obj in cache){
return cache[obj];//保存在cache中
}
return cache[obj]=getData();//从后台抓取的数据
}
})();
本文章参考:《Javascript设计模式与开发实践》—–AlloyTeam出品