一. 初识代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。它的用处就是当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问。通俗来讲就是,代理是一个中间人,负责在客户和卖家之间传递信息,将没用的信息过滤,将有利于交易成功的信息传递给卖家,从而加大交易的成功率。

二. 代理模式的实现思想

现在我们来通过一个小明给女神送花的例子来实现代理模式。

没有使用代理模式

        let Flower = function () {};
        let xiaomingFirst = {
            sendFlower ( target ) {
                let flower = new Flower();
                target.receiveFlower( flower );
            }
        }
        let A = {
            receiveFlower ( flower ) {
                console.log('收到花')
            }
        }
        xiaomingFirst.sendFlower(A);

使用代理模式重构

设定一个需求AA 为小明的女神,AA 在心情好的时候接受小明花的几率更大,而 B 是 AA 和小明的好朋友,因此小明将花送给 B,让 B 在 AA 心情好时转告自己的心意。

分析:重构后的代码增加了一个新的对象 B , 此时 为 AA 的代理,监听 AA 的好心情,代码中假定5秒后 AA 心情变好,将花送出。

        let xiaomingSencend = {
            sendFlower ( target ) {
                let flower = new Flower();
                target.receiveFlower( flower );
            }
        }
        let AA = {
            receiveFlower () {
                console.log('收到花');
            },
            listenGoodMood ( fn ) {
                setTimeout(()=>{
                    fn();
                }, 5000);
            }
        }
        let B = {
            receiveFlower ( flower ) {
                AA.listenGoodMood( ()=>{
                    AA.receiveFlower( flower );
                } );
            }
        }
        xiaomingSencend.sendFlower(B);

三. 代理模式分类

上述代码中代理模式可能显得不那么重要,但是体现了代理的思想,假如女神有一些要求,给他送花的男生必须帅而有钱,但又不能显得那么势力,因此代理可以帮其过滤掉这些不符合要求的男生,减少自己的许多麻烦,还能保持自己的美好形象这就是代理的用处。再者说,买一朵花很昂贵,而不是单单 new 这么简单,男生不想浪费自己的钱,因此想先确定女神是否接受自己的花,便让代理帮忙询问,如果女神接受则让代理帮忙买一朵送给女神,这样减少了男生的损失但也达成了目的,这便引出了以下两种代理模式。

  • 保护代理:本体的要求直接在代理中实现,过滤掉不符合的要求的访问者对本体的请求
  • 虚拟代理:将一些开销很大的操作等到准备向本体请求时候再实现(主要用于实际开发)

四. 虚拟代理模式的实际运用

1. 虚拟代理实现图片预加载

分析:先加载本地图片,然后开始发起请求获取图片,当图片加载获取成功后,再调用 myImage 将图片替换预加载时显示的图片。

    let myImage = function () {
        let img = document.createElement('img');
        document.body.appendChild(img);
        return {
            setSrc ( src ) {
                img.src = src;
            }
        }
    }();
    proxyImage = function () {
        let img = new Image;
        img.onload = function () {
            myImage.setSrc( this.src );
        }
        return {
            setProxyImage( src ) {
                myImage.setSrc("https://img.zcool.cn/community/01e2115d5d5c7da80120695c137bfb.jpg@1280w_1l_2o_100sh.jpg"); // 此处为加载 loading 图片,用来占位,本地图片(作者使用网络图片)
                img.src = src;
            }
        }
    }();
    proxyImage.setProxyImage("https://img.zcool.cn/community/01a5d45543cd170000019ae94fc087.jpg@1280w_1l_2o_100sh.jpg");

 2. 缓存代理

分析:在代理中将本体计算的结果进行缓存,如果下次再遇到同样的请求,直接从缓存中获取,减少对本体的访问,减少性能消耗。

        // 计算乘积的函数
        let mult = function (...arg) {
            console.log('我执行了')
            let m = 1;
            for(let i = 0,l = arg.length; i <l; i  ){
                m *= arg[i];
            }
            return m;
        }
        // 缓存代理
        let proxyMult = function( fn ) {
            let cache = {};
            return function (...arg) {
                let argS = arg.join(',');
                if( cache[argS] ) {
                    return cache[argS];
                }
                return cache[argS] = fn.apply( this, arg);
            }
        };
        let proxymult = proxyMult(mult);
        console.log(proxymult(1,2,4))

3. 虚拟代理合并 Http 请求

使用场景:点击复选框向服务器发起请求同步文件,每次点击复选框便发起一次请求,造成巨大网络开销,此时我们优化的方式为,将想同步的文件缓存下来,在 3 秒后通过一次请求发送到服务器。

    <input type="checkbox" >1
    <input type="checkbox" >2
    <input type="checkbox" >3
    <input type="checkbox" >4
    <input type="checkbox" >5
    <input type="checkbox" >6
    <input type="checkbox" >7
    <input type="checkbox" >8
    <script>
        // 同步文件
        let synchronousFile = function ( id ) {
            console.log("开始同步文件"   id);
        }
        // 代理实现同步文件
        let proxySynchronousFile = function ( ) {
            let cache = [];
            let time;
            return function ( id ) {
                cache.push( id );
                if( time ) {
                    return;
                }
                time = setInterval(() => {
                    synchronousFile(cache.join(','));
                    clearInterval(time);
                    time = null;
                    cache.length = 0;
                }, 3000);
            }
        }()
        // 添加点击执行
        let checkboxList = document.getElementsByTagName('input');
        for(let i = 0, l = checkboxList.length; i < l; i  ) {
            checkboxList[i].onclick = function() {
                if( this.checked === true ) { 
                    proxySynchronousFile(i 1);
                }
            }
        }

五. 代理的使用意义及要求

意义:首先我们引入面向对象设计原则,单一职责原则,一个对象应该尽可能少的承担职责,最好是一个,如果承担职责过多,会提高代码的耦合度,从而导致脆弱和低内聚的设计。当变化发生,设计可能遭到意外破坏,即使实现同样需求可以将代码封装到一个函数中,但是最好的处理措施是引入代理模式

要求:代理和本体接口要一致,在任何使用本体地方都可以用代理来代替

六. 总结

代理模式包括很多小模块,最常用的为缓存代理 和 虚拟代理,虽然代理模式非常有用,但我们再编写业务代码时不需要预先猜测是否需要使用代理模式,到发现不方便直接访问某个对象,真正使用时再编写也不迟。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注Devmax的更多内容!

javascript设计模式之订阅者模式的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部