• JS 设计模式 -代理模式


    代理模式简述

    代理是一个对象,跟本体对象具有相同的接口,以此达到对本体对象的访问控制。

    简单言之,本体对象只注重业务逻辑的实现,代理则控制本体对象的实例化(何时实例化、何时被使用)。

    代理模式的优点在于:代理对象可以代替本体对象被实例化,此时本体对象未真正实例化,等到合适时机再实例化。

    代理模式可以延迟创建开销很大的本体对象,他会把本体的实例化推迟到有方法被调用时。

    一个简单的例子

    // 声明女孩对象
    var girl = function (name) {
        this.name = name;
    };
    // 声明男孩对象
    var boy = function (girl) {
        this.girl = girl;
        this.sendGift = function (gift) {
            alert("Hi " + girl.name + ", 男孩送你一个礼物:" + gift);
        }
    };
    // 声明代理对象
    var proxyObj = function (girl) {
        this.girl = girl;
        this.sendGift = function (gift) {
            (new boy(girl)).sendGift(gift); // 替dudu送花咯
        }
    };
    var proxy = new proxyObj(new girl("花花"));
    proxy.sendGift("999朵玫瑰");
    

    如上代码,girl是一个被送礼物的对象,boy是送礼物的对象,他保存了girl这个属性,还有一个送礼物的方法sendGift,然后他通过proxyObj去完成这件事,proxyObj就是代理,他把boy的礼物送给了girl,因此proxyObj同样需要保存girl的属性,同时也有sendGift方法,该方法实例化本体对象boy并调用了boy的sendGift方法,完成了boy送girl礼物的这个过程。

    实战一:图片加载

    在前端开发中,使用图片是非常常见的场景,如果直接给img标签设置src属性,如果图片过大,或网速比较慢,图片在加载过程中会有一段时间的空白,用户体验不好。

    传统的解决方案

    传统的解决方法是:在图片未加载完成之前,使用一个loading图标作为占位符,等图片完成加载后,再使用真实的图片地址替代loading图标。如下:

    // 不使用代理的预加载图片函数如下
    var myImage = (function(){
        var imgNode = document.createElement("img");
        document.body.appendChild(imgNode);
        var img = new Image();
        img.onload = function(){
            imgNode.src = this.src;
        };
        return {
            setSrc: function(src) {
                imgNode.src = "http://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif";
                img.src = src;
            }
        }
    })();
    // 调用方式
    myImage.setSrc("https://www.baidu.com/img/bd_logo1.png");
    

    如上代码,这是使用一般的编码方式实现图片的预加载技术的方案,首先创建imgNode元素,然后调用myImage.setSrc该方法的时候,先给图片一个预加载图片,当图片加载完的时候,再给img元素赋值。

    这种方案是可以实现功能,但也有比较明显的缺陷:耦合性太高,myImage函数违背了面向对象设计原则中的单一职责原则,同时完成了创建img,设置loading加载状态等多个任务。

    此时就可以使用代理模式来实现~~~

    代理模式解决方案

    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://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif");
            img.src = src;
            }
        }
    })();
    // 调用方式
    ProxyImage.setSrc("https://www.baidu.com/img/bd_logo1.png");
    

    如上代码,myImage 函数只负责做一件事,创建img元素加入到页面中,其中的加载loading图片交给代理函数ProxyImage 去做,当图片加载成功后,代理函数ProxyImage 会通知及执行myImage 函数的方法,同时当以后不需要代理对象的话,我们直接可以调用本体对象的方法即可。

    代理模式跟本体对象具有相同的对外接口,有两个好处:
    一、用户可以放心地请求代理,不需要了解代理的实现过程,只要结果符合预期即可。如果不需要代理对象了,可以换成调用本体对象的该方法
    二、在任何使用本体对象的地方,都可以使用代理替换。

    最后,强调一点,主体对象跟代理对象也可以都返回一个匿名函数,这样也认为他们具有相同的接口。

    实战二:缓存代理

    对第一次运行的结果进行缓存,当再一次运行相同运算的时候,直接从缓存里面取,避免重复运算,如果运算非常复杂的话,对性能很耗费,那么使用缓存对象可以提高性能。以下是一个简单的例子:

    var mult = function(){
        var a = 1;
        for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
            a = a*arguments[i];
        }
        return a;
    };
    // 计算加法
    var plus = function(){
        var a = 0;
        for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
            a += arguments[i];
        }
        return a;
    }
    // 代理函数
    var proxyFunc = 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 = proxyFunc(mult);
    console.log(proxyMult(1,2,3,4)); // 24
    console.log(proxyMult(1,2,3,4)); // 缓存取 24
    
    var proxyPlus = proxyFunc(plus);
    console.log(proxyPlus(1,2,3,4));  // 10
    console.log(proxyPlus(1,2,3,4));  // 缓存取 10
    

    如上代码就是网上常见的加法和乘法的运算。通过缓存代理,可以减少不必要的运算量。



    作者:5d18ee6b5b1c
    链接:https://www.jianshu.com/p/46b0756c92a0
    来源:简书

  • 相关阅读:
    Python股票分析系列——系列介绍和获取股票数据.p1
    快速相关
    特别长序列的快速卷积
    长序列的快速卷积
    快速卷积
    素因子快速傅里叶变换
    用一个N点复序列的FFT同时计算两个N点实序列离散傅里叶变换
    实序列快速傅里叶变换(二)
    实序列快速傅里叶变换(一)
    java 对于手机号码、邮箱、银行卡号脱敏一条龙服务
  • 原文地址:https://www.cnblogs.com/chendahao/p/12218070.html
Copyright © 2020-2023  润新知