JavaScript设计模式

来源:互联网 发布:网络通信安全员证书 编辑:程序博客网 时间:2024/06/07 22:28
一、单体模式
概念:单体模式是一个用来划分命名空间并将一批相关的属性和方法组织在一起的对象,如果他可以被实例化,那么他只能被实例化一次。
优点
1. 可以来划分命名空间,从而清除全局变量所带来的危险。
2. 利用分支技术来来封装浏览器之间的差异。
3. 可以把代码组织的更为一体,便于阅读和维护。
实例

var singleton = function( fn ){    var result;    return function(){        return result || ( result = fn .apply( this, arguments ) );    }} var createMask = singleton( function(){ return document.body.appendChild( document.createElement('div') );  })
二、工厂模式
概念:提供创建对象的接口,意思就是根据领导(调用者)的指示(参数),生产相应的产品(对象)。
1.简单工厂模式:使用一个类(通常为单体)来生成实例。
实例:
var XMLHttpFactory =function(){};      //这是一个简单工厂模式  XMLHttpFactory.createXMLHttp =function(){    var XMLHttp = null;    if (window.XMLHttpRequest){      XMLHttp = new XMLHttpRequest()    }else if (window.ActiveXObject){      XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")    }  return XMLHttp;  }  //XMLHttpFactory.createXMLHttp()这个方法根据当前环境的具体情况返回一个XHR对象。  var AjaxHander =function(){    var XMLHttp = XMLHttpFactory.createXMLHttp();    ...  }
2.复杂工厂模式:将其成员对象的实列化推到子类中,子类可以重写父类接口方法以便创建的时候指定自己的对象类型。
实例:
var XMLHttpFactory =function(){};      //这是一个抽象工厂模式XMLHttpFactory.prototype = {  //如果真的要调用这个方法会抛出一个错误,它不能被实例化,只能用来派生子类  createFactory:function(){    throw new Error('This is an abstract class');  }}var XHRHandler =function(){}; //定义一个子类// 子类继承父类原型方法extend( XHRHandler , XMLHttpFactory );XHRHandler.prototype =new XMLHttpFactory(); //把超类原型引用传递给子类,实现继承XHRHandler.prototype.constructor = XHRHandler; //重置子类原型的构造器为子类自身//重新定义createFactory 方法XHRHandler.prototype.createFactory =function(){  var XMLHttp =null;  if (window.XMLHttpRequest){         XMLHttp =new XMLHttpRequest();  }else if (window.ActiveXObject){    XMLHttp =new ActiveXObject("Microsoft.XMLHTTP")  }  return XMLHttp;}
应用场景:
(1)对象的构建十分复杂
(2)需要依赖具体环境创建不同实例
(3)处理大量具有相同属性的小对象
三、观察者模式
概念:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新,也被称为是发布订阅模式。
实现步骤
   1. 确定发布者;
   2. 给发布者添加一个缓存列表,用于存放回调函数来通知订阅者;
   3. 发布消息时,需要遍历这个缓存列表,依次触发里面存放的订阅者回调函数;
   4、退订,从缓存列表中移除;
实例
var Event = (function(){    var list = {},          listen,          trigger,          remove;//订阅消息          listen = function(key,fn){            if(!list[key]) {                list[key] = [];            }            list[key].push(fn);        };//发布消息触发        trigger = function(){            var key = Array.prototype.shift.call(arguments),                 fns = list[key];            if(!fns || fns.length === 0) {                return false;            }            for(var i = 0, fn; fn = fns[i++];) {                fn.apply(this,arguments);            }        };        remove = function(key,fn){            var fns = list[key];            if(!fns) {                return false;            }            if(!fn) {                fns && (fns.length = 0);            }else {                for(var i = fns.length - 1; i >= 0; i--){                    var _fn = fns[i];                    if(_fn === fn) {                        fns.splice(i,1);                    }                }            }        };        return {            listen: listen,            trigger: trigger,            remove: remove        }})();// 测试代码如下:Event.listen("color",function(size) {    console.log("尺码为:"+size); // 打印出尺码为42});Event.trigger("color",42);
三、策略模式
概念:指的是定义一系列的算法,把他们一个个封装起来,目的就是将算法的使用与算法的实现分离开来。说白了就是以前要很多判断的写法,现在把判断里面的内容抽离开来,变成一个个小的个体即策略。
实例
//超市促销定价// 对于vip客户function vipPrice() {    this.discount = 0.5;} vipPrice.prototype.getPrice = function(price) {  return price * this.discount;}// 对于老客户function oldPrice() {    this.discount = 0.3;} oldPrice.prototype.getPrice = function(price) {    return price * this.discount;}// 对于普通客户function Price() {    this.discount = 1;} Price.prototype.getPrice = function(price) {    return price ;}// 上下文,对于客户端的使用function Context() {    this.name = '';    this.strategy = null;    this.price = 0;} Context.prototype.set = function(name, strategy, price) {    this.name = name;    this.strategy = strategy;    this.price = price;}Context.prototype.getResult = function() {    console.log(this.name + ' 的结账价为: ' + this.strategy.getPrice(this.price));}var context = new Context();var vip = new vipPrice();context.set ('vip客户', vip, 200);context.getResult();   // vip客户 的结账价为: 100var old = new oldPrice();context.set ('老客户', old, 200);context.getResult();  // 老客户 的结账价为: 60var Price = new Price();context.set ('普通客户', Price, 200);context.getResult();  // 普通客户 的结账价为: 200
四、模板模式
概念:定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通俗的讲,就是将一些公共方法封装到父类,子类可以继承这个父类,并且可以在子类中重写父类的方法,从而实现自己的业务逻辑。
实例
var Interview = function(){};// 笔试Interview.prototype.writtenTest = function(){    console.log("这里是前端笔试题");};// 技术面试Interview.prototype.technicalInterview = function(){    console.log("这里是技术面试");}; // 领导面试Interview.prototype.leader = function(){    console.log("领导面试");};// 领导面试Interview.prototype.HR = function(){    console.log("HR面试");};// 等通知Interview.prototype.waitNotice = function(){    console.log("等通知啊,不知道过了没有哦");};// 代码初始化Interview.prototype.init = function(){    this.writtenTest();    this.technicalInterview();    this.leader();    this.HR();    this.waitNotice();};// 阿里巴巴的笔试和技术面不同,重写父类方法,其他继承父类方法。var AliInterview = function(){};AliInterview.prototype = new Interview();// 子类重写方法 实现自己的业务逻辑AliInterview.prototype.writtenTest = function(){    console.log("阿里的技术题就是难啊");}AliInterview.prototype.technicalInterview = function(){    console.log("阿里的技术面就是叼啊");}var AliInterview = new AliInterview();AliInterview.init();
五、代理模式
概念:是指把对一个对象的访问, 交给另一个代理对象来操作。
实例
// 补打卡事件var fillOut = function (lateDate) {    this.lateDate = lateDate;};// 这是bigBossvar bigBoss = function (fillOut) {    this.state = function (isSuccess) {        console.log("忘记打卡的日期为:" + fillOut.lateDate + ", 补打卡状态:" + isSuccess);    }};// 助理代理大boss 完成补打卡审批var proxyAssis = function (fillOut) {    this.state = function (isSuccess) {        (new bigBoss(fillOut)).state(isSuccess); // 替bigBoss审批    }};// 调用方法:var proxyAssis = new proxyAssis(new fillOut("2016-9-11"));proxyAssis.state("补打卡成功");
图片预加载应用案例:
var myImage = (function(){    var imgNode = document.createElement("img");    document.body.appendChild(imgNode);    return function(src){        imgNode.src = src;     }})();// 代理模式var ProxyImage = (function(){    var img = new Image();    img.onload = function(){        myImage(this.src);    };    return function(src) {                // 占位图片loading                myImage("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif");        img.src = src;    }})();// 调用方式ProxyImage("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png"); // 真实要展示的图片
六、职责链模式
概念:职责连是由多个不同的对象组成的,发送者是发送请求的对象,而接收者则是链中那些接收这种请求并且对其进行处理或传递的对象。
基本实现流程如下
1. 发送者知道链中的第一个接收者,它向这个接收者发送该请求。
2. 每一个接收者都对请求进行分析,然后要么处理它,要么它往下传递。
3. 每一个接收者知道其他的对象只有一个,即它在链中的下家(successor)。
4. 如果没有任何接收者处理请求,那么请求会从链中离开。   
实例
//充值抽红包  function order500(orderType,isPay,count){    if(orderType == 1 && isPay == true)    {        console.log("亲爱的用户,您中奖了100元红包了");    }else {        //我不知道下一个节点是谁,反正把请求往后面传递        return "nextSuccessor";    }};function order200(orderType,isPay,count) {    if(orderType == 2 && isPay == true) {        console.log("亲爱的用户,您中奖了20元红包了");    }else {        //我不知道下一个节点是谁,反正把请求往后面传递        return "nextSuccessor";    }};function orderNormal(orderType,isPay,count){    // 普通用户来处理中奖信息    if(count > 0) {        console.log("亲爱的用户,您已抽到10元优惠卷");    }else {        console.log("亲爱的用户,请再接再厉哦");    }}// 下面需要编写职责链模式的封装构造函数方法var Chain = function(fn){    this.fn = fn;    this.successor = null;};Chain.prototype.setNextSuccessor = function(successor){    return this.successor = successor;}// 把请求往下传递Chain.prototype.passRequest = function(){    var ret = this.fn.apply(this,arguments);    if(ret === 'nextSuccessor') {        return this.successor && this.successor.passRequest.apply(this.successor,arguments);    }    return ret;}//现在我们把3个函数分别包装成职责链节点:var chainOrder500 = new Chain(order500);var chainOrder200 = new Chain(order200);var chainOrderNormal = new Chain(orderNormal);// 然后指定节点在职责链中的顺序chainOrder500.setNextSuccessor(chainOrder200);chainOrder200.setNextSuccessor(chainOrderNormal);//最后把请求传递给第一个节点:chainOrder500.passRequest(1,true,500);  // 亲爱的用户,您中奖了100元红包了chainOrder500.passRequest(2,true,500);  // 亲爱的用户,您中奖了20元红包了chainOrder500.passRequest(3,true,500);  // 亲爱的用户,您已抽到10元优惠卷 chainOrder500.passRequest(1,false,0);   // 亲爱的用户,请再接再厉哦
七、命令模式
概念:命令模式指的是一个执行某些特定事情的指令。
实例
// 如下代码上的四个按钮 点击事件var b1 = document.getElementById("button1"),    b2 = document.getElementById("button2"),    b3 = document.getElementById("button3"),    b4 = document.getElementById("button4");/* bindEnv函数负责往按钮上面安装点击命令。点击按钮后,会调用 函数 */var bindEnv = function(button,func) {    button.onclick = function(){        func();    }};// 现在我们来编写具体处理业务逻辑代码var Todo1 = {    test1: function(){        alert("我是来做第一个测试的");    }    };// 实现业务中的增删改操作var Menu = {    add: function(){        alert("我是来处理一些增加操作的");    },    del: function(){        alert("我是来处理一些删除操作的");    },    update: function(){        alert("我是来处理一些更新操作的");    }};// 调用函数bindEnv(b1,Todo1.test1);// 增加按钮bindEnv(b2,Menu.add);// 删除按钮bindEnv(b3,Menu.del);// 更改按钮bindEnv(b4,Menu.update);
八、备忘录模式
备忘录模式在js中经常用于数据缓存. 比如一个分页控件, 从服务器获得某一页的数据后可以存入缓存,以后再翻回这一页的时候,可以直接使用缓存里的数据而无需再次请求服务器。
实例
var Page = function(){   var page = 1,      cache = {},      data;   return function( page ){      if ( cache[ page ] ){               data =  cache[ page ];               render( data );      }else{               Ajax.send( 'cgi.xx.com/xxx', function( data ){                   cache[ page ] = data;                   render( data );               })      }    }}()

参考:

1. 常用的javascript设计模式

2. javascript设计模式详解

3. javascript常用的设计模式


原创粉丝点击