• JavaScript设计模式_03_代理模式


    代理模式是非常常见的模式,比如我们使用的VPN工具,明星的经纪人,都是代理模式的例子。但是,有人会疑问,明明可以直接访问对象,为什么中间还要加一个壳呢?这也就说到了代理模式的好处。在我看来,代理模式最大的好处,就是在不动原有对象的同时,可以给原有对象增加一些新的特性或者行为。

    /**
     * pre:代理模式
     * 小明追求A,B是A的好朋友,小明比较腼腆,不好意思直接将花交给A,
     * 于是小明将花交给B,再由B交给A.
     */
    //----------- 示例1 ---------
    // 不使用代理
    var Flower = function() {};
    var xiaoming = {
        sendFlower: function(target) {
            var flower = new Flower();
            target.receiveFlower(flower);
        }
    };
    var A = {
        receiveFlower: function(flower) {
            console.log("收到花:" + flower);
        }
    };
    xiaoming.sendFlower(A);
    
    // ----------- 示例2 --------------
    // 使用代理1
    var Flower = function() {};
    var xiaoming = {
        sendFlower: function(target) {
            var flower = new Flower();
            B.receiveFlower(flower);
        }
    };
    var B = {
        receiveFlower: function(flower) {
            A.receiveFlower(flower);
        }
    };
    var A = {
        receiveFlower: function(flower) {
            console.log("收到花:" + flower);
        }
    };
    xiaoming.sendFlower(B);
    
    //------------- 示例3 ---------------
    /* 
     * 使用代理2
     * 从示例1和示例2,看不出使用代理有什么用处,B只不过是从中间转手了一次。
     * 接下来,我们想一下。给喜欢的人送花,怎样才能提高成功率呢?
     * 我们都知道,人有心情好和心情差的时候,当美女心情好的时候,送花成功的概率自然要大些。
     * 于是,我们将代理升级,监听美女的心情,心情好的时候再给她送花。
     * 为了演示,我们假设2秒后,A的心情变好。
     */
    
    var Flower = function() {};
    var xiaoming = {
        sendFlower: function(target) {
            var flower = new Flower();
            B.receiveFlower(flower);
        }
    };
    var B = {
        receiveFlower: function(flower) {
            A.listenGoodMood(function() {
                A.receiveFlower(flower);
            });
        }
    };
    var A = {
        receiveFlower: function(flower) {
            console.log("收到花:" + flower);
        },
        listenGoodMood: function(fn) {
            setTimeout(function() {
                fn.apply(this, arguments);
            }, 2000);
        }
    };
    xiaoming.sendFlower(B);
    // ---------- 示例4 ---------------
    /*
     * 【代理模式用处】:虚拟代理
     * 这里以加载图片为例,我们都知道当网络不畅以及图片过大时,图片加载都比较慢,
     * 为了更好的用户体验,我们都会在原图片未加载完成前,加上loading图片。
     * */
    //--4 _01未使用代理--
    var myImage = (function() {
        var imgNode = document.createElement("img");
        document.body.appendChild(imgNode);
        return {
            setSrc: function(src) {
                this.imgNode.src = src;
            }
        }
    })();
    myImage.setSrc("xxx");
    //--4_02使用代理--
    var proxyMyImage = (function() {
        var img = new Image();
        img.onload = function() {
            myImage.setSrc(this.src);
        };
        return {
            setSrc: function(src) {
                myImage.setSrc("loading.jpg");
                img.src = src;
            }
        }
    })();
    proxyMyImage.setSrc("xxx");
    /*
     * [注]:这里可以看到代理模式的好处:在不改变原有接口的同时,可以为系统添加新的行为。
     */
    //--------- 示例5---------------
    /*
     * 【代理模式用处】:合并http请求
     * 这里以选择文件同步为例。
     * 以往用户同步文件,在用户选中的时候就触发,这种方法做到了实时性,但无疑增加了网络的开销。
     * 实际在使用的过程中,往往并不需要立刻就同步。
     * 以下通过代理模式,将在用户选中文件2秒后进行同步请求。
     * */
    // --- 包含一段html代码,请自行添加到一个文件中 ------
    <html>
        <body>
            <button id="input">点我上传</button>
            <input type="checkbox" id="1"></input>1
            <input type="checkbox" id="2"></input>2
            <input type="checkbox" id="3"></input>3
            <input type="checkbox" id="4"></input>4
            <input type="checkbox" id="5"></input>5
            <input type="checkbox" id="6"></input>6
            <input type="checkbox" id="7"></input>7
            <input type="checkbox" id="8"></input>8
            <input type="checkbox" id="9"></input>9
        </body>
    </html>
    // -- 上传文件 --
    var synchronizeFile = function(id) {
        console.log("开始同步文件:" + id);
    };
    var proxySynchronizeFiles = (function() {
        var fileCache = [],
            timer;
        return function(id) {
            fileCache.push(id);
            if(timer) {
                return;
            }
            timer = setTimeout(function() {
                synchronizeFile(fileCache.join(","));
                clearTimeout(timer);
                timer = null;
                checkArr.length = 0;
            }, 2000);
        }
    })();
    var checkArr = document.getElementsByTagName("input");
    for(var i = 0, c; c = checkArr[i++];) {
        c.onclick = function() {
            if(this.checked == true) {
                proxySynchronizeFiles(this.id);
            }
        }
    }
    // ------------ 示例6 -----------------
    /*
     * 【代理模式用处】:缓存代理
     *  以计算器为例,比如计算某些数的乘积,当参数重复时,我们希望不用重复计算,直接返回结果。
     *  以下用到代理模式做缓存。
     */
    var mult = function() {
        if(!arguments) {
            console.log("请输入参数");
            return;
        }
        var a = 1;
        for(var i = 0, b; b = arguments[i++];) {
            a = a * b;
        }
        return a;
    };
    
    var proxyMult = (function() {
        var cache = {};
        return function() {
            var str = Array.prototype.join.call(arguments, ",");
            if(str in cache) {
                console.log("重复return.");
                return cache[str];
            }
            return cache[str] = mult.apply(this, arguments);
        }
    })();
    
    console.log(proxyMult(2, 3, 4));
    console.log(proxyMult(2, 3, 4));
    //------------ 示例7 --------------
    /*
     * 缓存代理升级 - 通用版计算
     * 
     */
    var mult = function() {
        if(!arguments) {
            return;
        }
        var t = 1;
        for(var i = 0, a; a = arguments[i++];) {
            t = t * a;
        }
        return t;
    };
    var plus = function() {
        if(!arguments) {
            return;
        }
        var t = 0;
        for(var a of arguments) {
            t += a;
        }
        return t;
    };
    var createProxyCaculate = function(fn) {
        var cache = {};
        return function() {
            var str = Array.prototype.join.call(arguments, ",");
            if(str in cache) {
                console.log("重复return" + str);
                return cache[str];
            }
            return cache[str] = fn.apply(this, arguments);
        }
    };
    var proxyMult = createProxyCaculate(mult);
    var proxyPlus = createProxyCaculate(plus);
    console.log(proxyMult(2, 3, 4));
    console.log(proxyMult(2, 3, 4));
  • 相关阅读:
    (SPOJ4)Transform the Expression
    Minix2.0操作系统kernel文件分析
    Minix2.0内核源代码的组织结构
    powerdesigner教程系列(三)
    多线程
    软件架构师成长之路
    保护sqlconnection的链接字符串中的密码不泄露
    powerdesigner教程系列(四)
    [Serializable]在C#中的作用.NET 中的对象序列化
    vps经典文章
  • 原文地址:https://www.cnblogs.com/stinchan/p/6971277.html
Copyright © 2020-2023  润新知