设计模式之代理模式

Posted by franki on November 2, 2018

proxy

代理模式

为一个对象提供一个代用品或占位符,以便控制对它的访问

(1)代理模式实现预加载

// 本体对象
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(http://help.leadsquared.com/wp-content/themes/help/images/Spinner_t.gif
            );
            img.src = src;
        }
    }
})();

proxyImage.setSrc("http://img.zcool.cn/community/0117e2571b8b246ac72538120dd8a4.jpg@1280w_1l_2o_100sh.jpg"
);

现在通过proxyImage间接地访问myImage.proxyImage控制了客户对myImage的访问,并在此将入了其他的操作,比如在图片加载完成之前,先把img节点的src设置为一张gif的loading图片

在静态语言中,往往本体和代理都要有相同的接口,来保证它们会拥有相同的方法。但在javascript中,大多数情况下没有做类型检测,对于一门快速开发的脚本语言来说,这些影响都是可接受的。

把本体和代理对象都为一个函数,函数都能被执行,则认为它们有一致的接口。

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) {
        myImage(http://help.leadsquared.com/wp-content/themes/help/images/Spinner_t.gif’) ;
        img.src = src;
    }
})();

proxyImage(http://img.zcool.cn/community/0117e2571b8b246ac72538120dd8a4.jpg@1280w_1l_2o_100sh.jpg’);

(2)虚拟代理合并http请求 假如有这样的一个需求,用户点击某个复选框要实时同步到另外一台服务器,如果没点击一次就要同步一次,那么对于服务器的压力无疑是巨大的,所以这个时候有;使用虚拟代理模式合并某段时间内需要同步的文件,这样对于减轻服务器的压力的效果是杠杠的。

<div id="app">
    <input type='checkbox' id='1' />1
    <input type='checkbox' id='2' />2
    <input type='checkbox' id='3' />3
    <input type='checkbox' id='4' />4
    <input type='checkbox' id='5' />5
    <input type='checkbox' id='6' />6
    <input type='checkbox' id='7' />7
    <input type='checkbox' id='8' />8
    <input type='checkbox' id='9' />9
</div>

正文如下

var syncFiles = function(file) {
console.log(需要同步的文件id为 ,  file);
}

var proxySyncFiles = (function() {
    var timer, cache = [];
    return function(file) {
        cache.push(file);
        if (timer) return; // 保证不会覆盖已经存在的定时器
        timer = setTimeout(function() {
            syncFiles(cache.join(,));
            clearTimeout(timer);
            timer = null;
            cache.length = 0;
        }, 2000);
    }
})();

var checkboxs = document.getElementByTagName(input);

for (var i = 0, c;c=checkboxs[i++];) {
    if (!this.checked) retrun;
    c.onclick = function() {
        proxySyncFiles(this.id);
    };
}

(3)缓存代理 可以为一些开销大的运算结果提供暂时的存储,在下次进来的时候,如果传递进来的参数跟之前的一致,则可以直接返回前面存储的运算结果。

//计算乘积
var muti = function(){
    var a = 1, args = arguments;
    for(var i=0, len=arguments.length;i<len;i++){
        a = a*args[i];
    }
    return a;
}

//已经计算过的结果,直接返回,无需重新计算
var proxyMuti = (function(){
    var cache = {};
    return function(){
        var arg = Array.prototype.join.call(arguments);
        if (arg in cache){
            console.log('缓存数:', cache[arg]);
            return cache[arg];
        }
        return cache[arg] = muti.apply(this, arguments);
    }
})();

代理模式包括许多小分类,在 JavaScript 开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。 当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。