美文网首页
JavaScript 设计模式之代理模式

JavaScript 设计模式之代理模式

作者: 27亿光年中的小小尘埃 | 来源:发表于2019-11-27 22:50 被阅读0次

什么是代理模式?

首先我们先看一个有趣的例子

在四月一个晴朗的早晨,小明遇见了他的百分百女孩,我们暂且称呼小明的女神为A。两天之后,小明决定给A送一束花来表白。刚好小明打听到A和他有一个共同的朋友B,于是内向的小明决定让B来代替自己完成送花这件事情。虽然小明的故事必然以悲剧收场,因为追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,即小明通过B来给A送花:

// 首先的有花的实例
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( A );

很显然,执行结果跟第一段代码一致,至此我们就完成了一个最简单的代理模式的编写。

也许读者会疑惑,小明自己去送花和代理B帮小明送花,二者看起来并没有本质的区别,引入一个代理对象看起来只是把事情搞复杂了而已。

但是,假设当A在心情好的时候收到花,小明表白成功的几率有60%,而当A在心情差的时候收到花,小明表白的成功率无限趋近于0。

小明跟A刚刚认识两天,还无法辨别A什么时候心情好。如果不合时宜地把花送给A,花被直接扔掉的可能性很大,这束花可是小明吃了7天泡面换来的。

但是A的朋友B却很了解A,所以小明只管把花交给B,B会监听A的心情变化,然后选择A心情好的时候把花转交给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的好心情
            A.receiveFlower( flower );
        });
    }
};
// 女神
var A = {
    // 女神接收到了花
    receiveFlower: function( flower ){
        console.log( '收到花 ' + flower );
    },
    // 女神心情好了
    listenGoodMood: function( fn ){
        setTimeout(function(){ // 假设10秒之后A的心情变好
            fn();
        }, 10000 );
    }
};
// 小明开始送花
xiaoming.sendFlower( A );

虚拟代理

虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。

虚拟代理实现图片预加载

在Web开发中,图片预加载是一种常用的技术,如果直接给某个img标签节点设置src属性, 由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。

下面我们来实现这个虚拟代理,首先创建一个普通的本体对象,这个对象负责往页面中创建一个img标签,并且提供一个对外的setSrc接口,外界调用这个接口,便可以给该img标签设置src属性:

var myImage = (function(){
    var imgNode = document.createElement( 'img' );
    document.body.appendChild( imgNode );
    return {
        setSrc: function( src ){
        i   mgNode.src = src;
        }
    }
})();
myImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg')

引入虚拟代理模式

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( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
         img.src = src;
        }
    }
})();
proxyImage.setSrc( 'http://imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

现在我们通过proxyImage间接地访问MyImage。proxyImage控制了客户对MyImage的访问,并且在此过程中加入一些额外的操作,比如在真正的图片加载好之前,先把img节点的src设置为一张本地的loading图片。

缓存代理

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

缓存代理的例子——计算乘积

var mult = function(){
    console.log( '开始计算乘积' );
    var a = 1;
    for ( var i = 0, l = arguments.length; i < l; i++ ){
        a = a * arguments[i];
    }
    return a;
};
// 加入缓存代理
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 );
    }
})();
proxyMult( 1, 2, 3, 4 ); // 输出:24
proxyMult( 1, 2, 3, 4 ); // 输出:24

当我们第二次调用proxyMult(1,2,3,4)的时候,本体mult函数并没有被计算,proxyMult直接返回了之前缓存好的计算结果。

通过增加缓存代理的方式,mult函数可以继续专注于自身的职责——计算乘积,缓存的功能是由代理对象实现的。

其他代理模式

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

相关文章

  • [记录]我的设计模式学习路径

    书单 《JavaScript 设计模式与开发实践》《设计模式之美》《掘金小册-JavaScript 设计模式核⼼原...

  • JavaScript设计模式之代理模式

    介绍 使用者无权直接访问目标对象 中间使用代理,通过代理的方式做授权和控制 实例 科学上网 明星经纪人 UML 代...

  • JavaScript 设计模式之代理模式

    什么是代理模式? 首先我们先看一个有趣的例子 在四月一个晴朗的早晨,小明遇见了他的百分百女孩,我们暂且称呼小明的女...

  • JavaScript设计模式四(代理模式)

    JavaScript设计模式四(代理模式) 代理模式的定义: 代理模式是为一个对象提供一个代用品或者占位符,以便对...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • 代理模式

    设计模式之代理模式 什么是代理模式? 指的事代理对象为其他对象提供代理以控制对被...

  • JavaScript设计模式之代理模式(Proxy)

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。 代理模式的关键是,当客户不方便直接访问一个对象或...

  • Javascript设计模式-代理模式

    特点 1.使用者无法直接访问目标对象 2.使用者和目标对象之间加一层代理,通过代理来授权和控制 例如:访问gith...

  • JavaScript设计模式——代理模式

    代理模式 代理的概念 由于一个对象不能直接引用另一个对象,所以需要通过代理对象在这两个对象之间起到中介的作用 以上...

  • JavaScript设计模式——代理模式

    代理模式属于设计模式中结构型的设计模式; 定义:顾名思义就是为一个对象提供一个代用品或占位符,以便控制对它的访问!...

网友评论

      本文标题:JavaScript 设计模式之代理模式

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