美文网首页
第6章代理模式

第6章代理模式

作者: 入秋未凉的海 | 来源:发表于2017-10-09 17:36 被阅读0次

    第6章代理模式

    6.1 第一个例子--小明追MM的故事

    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);
    

    引入代理B

    var Flower = function () {};
    
    var xiaoming = {
        sendFlower : function(target){
            var flower = new Flower();
            target.receiveFlower(flower);
        }
    }
    
    var B = {
        receiveFlower:function(flower){
            A.receiveFlower(flower)
        }
    }
    var A = {
        receiveFlower:function(flower){
            console.log('收到花'+flower);
        }
    }
    
    xiaoming.sendFlower(B);
    

    B会监听A的心情变化

    var Flower = function () {};
    
    var xiaoming = {
        sendFlower : function(target){
            var flower = new Flower();
            target.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();
            },3000);
    
        }
    }
    
    xiaoming.sendFlower(B);
    

    6.2 保护代理和虚拟代理

    比如送花的人中年龄太大或者没有宝马,这种请求就可以直接在代理B处被拒绝掉,这种代理叫保护代理。

    白脸A继续保持良好的女神形象,不希望直接拒绝任何人,于是找了黑脸B来控制对A的访问

    代理B会在A心情好时再执行new Flower,这叫虚拟代理,它会把一些开销很大的对象,延迟到真正需要它的时候才去创建

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

    在Javascript中并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,本章主要讨论的也是虚拟代理。

    6.3 虚拟代理实现图片预加载

    var myImage = (function(){
        // body...
        var imgNode = document.createElement('img');
        document.body.appendChild(imgNode);
    
        return {
            setSrc : function(src){
                imgNode.src = src;
            }
        }
    })();
    
    var proxyImage = (function(){
        var img = new Image;
        img.load = function(){
            myImage.setSrc(this.src);
        }
        return {
            setSrc:function(src){
                myImage.setSrc('file://jdjisj.gif');
                img.src = src;
            }
        }
    
    })()
    
    myImage.setSrc('http:wwjjfjds.jpg');
    

    6.4 代理的意义

    不用代理的预加载图片函数实现

    var myImage = (function(){
        var imgNode = document.createElement('img');
        document.body.appendChild(imgNode);
        var img = new Image;
    
        img.onload = function(){
            imgNode.src = img.src;
        };
    
        return {
            setSrc:function(){
                imgNode.src = 'file://dsd.gif';
                img.src = src;
            }
        }
    })()
    
    MyImage.setSrc('http://dsadsd.jpg');
    

    面向对象设计的原则--单一职责原则

    面向对象设计鼓励将行为分布到细粒度的对象之中,如果一个对象承担的职责过多,等于把这些职责耦合到了一起,这中耦合会导致脆弱和低内聚的设计。当发生变化时,设计可能会遭到意外的破环。

    面向对象程序中,大多数情况下,若违反其他任何原则,同时将违反开放-封闭原则。这时删预加载代码就不得不动MyImage对象了

    代理负责预加载图片完成后把请求重新交给本体。

    不需要预加载了只需要改成请求本体而不是请求代理对象即可

    6.5 代理和本体接口的一致性

    代理对象和本体都对外提供了setSrc方法,在客户看来,代理对象和本体是一致的,代理接手请求的过程对于用户来说是透明的,用户并不清楚代理和本体的区别。

    • 用户可以放心的请求代理,他只关心是否能得到想要的结果

    • 在任何使用本体的地方都可以替换成使用代理

    在Javascript这种语言中,我们有时通过鸭子类型来检测代理和本体是否都实现了setSrc方法,另外大多数时候甚至不做检测,全部依赖程序员的自觉性

    没有接口的世界

    如果代理对象和本体对象都为一个函数(函数也是对象),函数必然都能被执行,则可以认为它们也具有一致的“接口”

    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('file:fsfdf.gif');
            img.src = src;
        }
    })();
    
    proxyImage('http://sds.jpg');
    

    6.6 虚拟代理合并HTTP请求

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <input type="checkbox" name="" id="1">1
    <input type="checkbox" name="" id="2">2
    <input type="checkbox" name="" id="3">3
    <input type="checkbox" name="" id="4">4
    <input type="checkbox" name="" id="5">5
    <input type="checkbox" name="" id="6">6
    <input type="checkbox" name="" id="7">7
    <input type="checkbox" name="" id="8">8
    <input type="checkbox" name="" id="9">9
    
    <script>
        var synchronousFile = function(id){
            console.log('开始同步文件,id为:'+'id');
        }
        var checkbox = document.getElementsByTagName('input');
        for(var i = 0,c; c = checkbox[i++];){
            c.onclick = function(){
                if (this.checked === true) {
                    synchronousFile(this.id);
                }
            }
        }
    </script>
    </body>
    </html>
    

    如此频繁的网络请求将会带来相当大的开销

    var synchronousFile = function(id){
        console.log('开始同步文件,id为:' + id);
    }
    
    var proxySynchronousFile = (function(){
        var cache = [],timer;
        return function(id){
            cache.push(id);
            if(timer){
                return;
            }
            timer = setTimeout(function(){
                synchronousFile(cache.join(','));
                clearTimeout(timer);
                timer = null;
                cache.length = 0;
            },2000)
        }
    })();
    
    var checkbox = document.getElementsByTagName('input');
    for(var i = 0,c;c = checkbox[i++]){
        c.onclick = function(){
            if (this.checked ===true) {
                proxySynchronousFile(this.id);
            }
        }
    }
    

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

    var miniConsole = (function(){
        var cache = [];
        var handler = function(ev){
            if(ev.keyCode === 113){
                var script = document.createElement('script');
                script.onload = function(){
                    for(var i = 0, fn;fn = cache[i++];){
                        fn();
                    }
                }
                script.src = 'miniConsole.js';
                document.getElementsByTagName('head')[0].appendChild(script);
                document.body.removeEventListener('keydown',handler);//只加载一次miniConsole.js
            }
        };
        document.body.addEventListener('keydown',handler,false);
        return {
            log:function(){
                var args = arguments;
                cache.push(function(){
                    return miniConsole.log.apply(miniConsole,args);
                });
            }
        }
    })();
    
    miniConsole.log(11);
    
    //miniConsole.js代码
    miniConsole = {
        log:function(){
            //真正代码略
            console.log(Array.prototype.join.call(arguments));
        }
    }
    

    6.8 缓存代理

    6.8.1 缓存代理的例子--计算乘积

    var mult = function(){
        console.log('开始计算');
        var a = 1;
        for(var i=0, l = arguments.length;i<l;i++){
            a = a*arguments[i];
        }
        return a;
    }
    
    mult(2,3);//6
    mult(2,3,4);//24
    
    //加入缓存代理函数
    var proxyMult = (function(){
        var cache = {};
        return function(){
            var args = Array.prototype.join.call(arguments,',');
            if(args in cache){
                return cache[args];
            }
            return cache[args] = mult.apply(this,arguments);
        }
    })();
    
    var a = proxyMult(1,2,3,4); //24
    var b = proxyMult(1,2,3,4); //24
    console.log(a,b)
    开始计算
    24 24
    

    6.8.2 缓存代理用于ajax异步请求数据

    已经拉取的数据在某个地方被缓存之后,下次再请求同一页的时候,便可以直接使用之前的数据。

    这里也可以引入缓存代理,实现方式跟计算乘积的例子差不多,唯一不同的是,请求是个异步操作,我们无法把 计算结果放在代理对象的缓存中,而是通过回调的方式

    6.9 用高阶函数动态创建代理

    var mult = function(){
        var a = 1;
        for(var i = 0,l = arguments.length;i<l;i++){
            a = a*arguments[i];
        }
        return a;
    }
    
    var plus = function(){
        var a =0;
        for(var i = 0,l=arguments.length;i<l;i++){
            a = a + arguments[i]
        }
        return a;
    }
    
    var createProxyFactory = function(fn){
        var cache = {};
        return function(){
            var args =Array.prototype.join.call(arguments,',');
            if(args in cache){
                return cache[args];
            }
            return cache[args] = fn.apply(this,arguments);
        }
    };
    
    var proxyMult = createProxyFactory(mult);
    var proxyPlus = createProxyFactory(plus);
    
    console.log(proxyMult(1,2,3,4));
    console.log(proxyMult(1,2,3,4));
    console.log(proxyPlus(1,2,3,4));
    console.log(proxyPlus(1,2,3,4));
    

    6.10 其他代理模式

    防火墙模式:控制网络资源的访问,保护主题不让“坏人”接近
    远程代理:为一个对象在不同的地址空间提供局部代表,在JAVA中,远程代理可以是另一个虚拟机中的对象
    保护代理:用于对象应该有不同访问权限的情况。
    智能引用的次数:取代了简单的指针,它访问对象时执行一些附加操作,比如计算对象被引用的次数。
    写时复制代理:通常用于复制一个庞大对象的情况。写时复制代理延迟了复制的过程,当对象被真正修改时,才对它进行复制操作。写时复制代理是虚拟代理的一种变体,DLL(操作系统中的动态链接库)是其典型运用场景

    相关文章

      网友评论

          本文标题:第6章代理模式

          本文链接:https://www.haomeiwen.com/subject/lappyxtx.html