首页 > 代码库 > JavaScript设计模式 代理模式

JavaScript设计模式 代理模式

代理模式是为一个对象提供一个代用品或者占位符,以便控制对它的访问。

代理模式的关建是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际访问的是替身对象,替身对象对请求做出一些处理后,再把请求转交给本体对象。

先来看一个例子,假设A想送花给C,但又不知道C的心情,C的心情好时即送花成功,那么可以通过C的好朋友B来送花,B了解C,可以知道C的心情。

var Flower = function(){};
     //A发起送花请求
     var A = {
      sendFlower:function(target){
        var flower = new Flower();
         target.receiveFlower(flower);
      }
     };
     //B接受送花请求 并监听到C的心情好时转给C
     var B = {
         receiveFlower:function(flower){
           C.listenGoodMood(function(){
             C.receiveFlower(flower);
          });
         }
     };
     //C接受送花请求 和 发表心情
     var C = {
         receiveFlower :function(flower){
            console.log(flower);
         },
         listenGoodMood:function(fn){
           setTimeout(function(){
              fn();
           },1000)
         }
     };

     A.sendFlower(B);

在实际开发中,由于花的价格昂贵,那么可以当B监听到C的好心情时,才创建花来节省消耗。

var B = {
         receiveFlower:function(){
           C.listenGoodMood(function(){
            var  flower = new Flower();
             C.receiveFlower(flower);
          });
         }
     };

 

在这个例子中,最关键的就是B对象,也就是该章描述的代理对象,代理B可以帮助C过滤掉那些年龄太大之类的人,这些请求可以被B直接拒绝掉,这种被称为保护代理。而在真正需要的时候才来创建对象,也就是在C心情好的时候才创建花,被称为虚拟代理。

 

下面来看一个实际开发中的例子,通常在加载一个比较大的图片时,我们会先用一张菊花图提示用户化正在加载,当真正的图片被加载完成后,才显示该图片。

//加载图片的类
       var myImg = (function(){
           var imgNode = document.createElement(‘img‘);
           document.body.appendChild(imgNode);
           return {
              setSrc:function(src){
                 imgNode.src = src;
              }
           }
       })();
       //代理类,在图片加载完成之前 显示菊花图 加载完成后 改换真正的图片
       var proxyImg = (function(){
          var img = new Image();
          img.onload = function(){
             myImg.setSrc(this.src);
          };
          return {
             setSrc:function(src){
                myImg.setSrc("菊花图!");
                img.src = src;
             }
          }
       })();

       proxyImg.setSrc(‘真正的图片!‘);

在这里,也许会有疑问,即使不用代理模式也能实现这种效果,先来看一下不用代理的代码实现:

var myImg = (function(){
           var imgNode = document.createElement(‘img‘);
           document.body.appendChild(imgNode);
           var img = new Image();
           img.onload = function(){
             myImg.setSrc(this.src);
           };
           return {
              setSrc:function(src){
                 myImg.setSrc("菊花图!");
                 img.src = src;
              }
           }
       })();

       myImg.setSrc("真正的图片!")

为了说明代理的意义,先引入一个概念,即单一职责原则,表示一个类应该只有一个引起它变化的原因。这保证了类的高内聚和低耦合。

在不使用代理的例子下,myImg负责了给img设置src之外,还要负责预加载的图片,有时候我们的图片可能很小,或者以后的网速很快,那么我们就需要深入到该类来删除预加载的功能。

而如果采用了代理模式,那么当我们不需要预加载时,只需要直接调用myImg就可以了。

 

虚拟代理在惰性加载中的应用。

如一个控制台,当用户输入console.log(0)时,会在控制台打印0,但通常用户并不会一开始就打开控制台,所以也不会一开始就加载控制台。那么我们可以先创建一个代理类,将要打印的信息放进该代理类,当用户按下F12打开控制台的时候,我们创建了控制台之后,再遍历这些信息并输出。

 

代理在zepto类库事件处理中使用得比较多,具体可以参考zepto事件分析系列,其中带有proxy的即为代理对象。

 

参考自Javascript设计模式与开发实践一书。

JavaScript设计模式 代理模式