Maoyl's blog Maoyl's blog
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

maoyln

日日行,不怕千万里
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JS设计模式总结笔记
  • 单例模式
  • 代理模式
    • 代理模式
  • 事件代理(事件委托)
  • 策略模式
  • 《JavaScript设计模式》笔记
maoyln
2022-06-05
目录

代理模式


# 代理模式

# 概述

代理模式属于设计模式中结构型的设计模式;

# 定义:

顾名思义就是为一个对象提供一个代用品或占位符,以便控制对它的访问!

# 白话解释:

1.很多老板都有秘书,如果需要给老板写建议信,需要秘书现看一遍,秘书会把这些信件过滤一遍,然后在把有价值的信件给老板看;

2.我们找房子的时候很难去找到房东,房东发布租房信息也比较麻烦,这时候我们就会想到中介,中介其实也是一种代理模式,房东只需要给中介说我要出租房子,我们想要租房住的时候只需要找到中介即可。

# 实现方法
# 例子说明一:

小明遇见了他的百分百女孩,我们暂且称呼小明的女神为A。两天之后,小明决定给A送一東花来表白。刚好小明打听到A和他有一个共同的朋友B,于是内向的小明决定让B来代替自己完成送花这件事情

先看看不用代理方法

const Flower = function (){};
const xiaoming = {
    sendFlower: function(target) {
        const flower = new Flower();
        target.receiveFlower(flower);
    }
}

const A = {
    receiveFlower: function(flower) {
        console.log(`收到花${flower}`)
    }
};

xiaoming.sendFlower(A);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

接下来我们引用代理B,即小明通过B来给A送花

const Flower = function (){};
const xiaoming = {
    sendFlower: function(target) {
        const flower = new Flower();
        target.receiveFlower(flower);
    }
}

const B = {
    receiveFlower: function(flower) {
        A.receiveFlower(flower);
    }
}

const A = {
    receiveFlower: function(flower) {
        console.log(`收到花${flower}`)
    }
};

xiaoming.sendFlower(B);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

很显然,执行结果跟第一段代码一致,至此我们就完成了个最简单的代理模式的编写。也许读者会疑惑,小明自己去送花和代理B帮小明送花,者看起来并没有本质的区别,引入一个代理对象看起来只是把事情搞复杂了而已。

的确,此处的代理模式毫无用处,它所做的只是把请求简单地转交给本体。但不管怎样,我们开始引入了代理,这是一不错的起点。现在我们改变故事的背景设定,假设当A在心情好的时候收到花,小明表白成功的几率有60%,而当A在心情差的时候收到花,小明表白的成功率无限趋近于0。小明跟A刚刚认识两天,还无法辨别A什么时候心情好。如果不合时宜地把花送给A,花被直接扔掉的可能性很大,这束花可是小明吃了7天泡面换来的。但是A的朋友B却很了解A,所以小明只管把花交给B,B会监听A的心情变化,然后选择A心情好的时候把花转交给A,代码如下

const Flower = function (){};
const xiaoming = {
    sendFlower: function(target) {
        const flower = new Flower();
        target.receiveFlower(flower);
    }
}

const B = {
    receiveFlower: function(flower) {
        A.listenGoodMood(function() {
            // 监听A的好心情
            A.receiveFlower(flower);
        });
    }
}

const A = {
    receiveFlower: function(flower) {
        console.log(`收到花${flower}`);
    },
    listenGoodMood: function(fn) {
        setTimeout(function() { // 假设10秒后A的心情变好
            fn();
        }, 1000 * 5);
    }
};

xiaoming.sendFlower(B);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

保护代理和虚拟代理

虽然这只是个虚拟的例子,但我们可以从中找到两种代理模式的身影。代理B可以帮助A过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理B处被拒绝掉。这种代理叫作保护代理。A和B一个充当白脸,一个充当黑脸。白脸A继续保持良好的女神形象,不希望直接拒绝任何人,于是找了黑脸B来控制对A的访问。另外,假设现实中的花价格不菲,导致在程序世界里,neWFlower也是一个代价昂贵的操作,那么我们可以把new Flower的操作交给代理B去执行,代理B会选择在A心情好时再执行new Flower,这是代理模式的另一种形式,叫作虚拟代理。虛拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。代码如下

const B = {
    receiveFlower: function(flower) {
        A.listenGoodMood(function() {
            // 监听A的好心情
            var flower = new Flower(); // 延迟创建对象
            A.receiveFlower(flower);
        });
    }
};
1
2
3
4
5
6
7
8
9

保护代理用于控制不同权限的对象对目标对象的访问,但在Javascript并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,本章主要讨论的也是虚拟代理。当然上面只是一个虚拟的例子,我们无需在此投入过多近精力,接下来我们看另外一个真实的示例

# 例子说明二:虚拟代理实现图片懒加载

没用代理的时候我们的代码是这样的:

// 创建一个本体对象
var myImage = (function(){
  // 创建标签
  var imgNode = document.createElement( 'img' );
  // 添加到页面
  document.body.appendChild( imgNode );
  return {
    // 设置图片的src
    setSrc: function( src ){
      // 更改src
      imgNode.src = src;
    }
  }
})();
 
myImage.setSrc( 'https://www.maoyali.cn/img/ui.png' );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

我们把网速调至5KB/s,然后通过 Mylmage.setSrc给该img节点设置src,可以看到,在图片被加载好之前,页面中有一段长长的空白时间。现在开始引入代理对象 proxylmage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的菊花图loading gif,来提示用户图片正在加载。代码如下

// 创建一个本体对象
var myImage = (function(){
  // 创建标签
  var imgNode = document.createElement( 'img' );
  // 添加到页面
  document.body.appendChild( imgNode );
  return {
    // 设置图片的src
    setSrc: function( src ){
      // 更改src
      imgNode.src = src;
    }
  }
})();
 
// 创建代理对象
var proxyImage = (function(){
  // 创建一个新的img标签
  var img = new Image;
  // img 加载完成事件
  img.onload = function(){
    // 调用 myImage 替换src方法
    myImage.setSrc( this.src );
  }
  return {
    // 代理设置地址
    setSrc: function( src ){
      // 预加载 loading
      myImage.setSrc( './loading.gif' );
      // 赋值正常图片地址
      img.src = src;
    }
  }
})();
 
proxyImage.setSrc( 'https://www.maoyali.cn/img/ui.png' );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

上面这段代码运用代理模式来实现图片预加载,可以看到通过代理模式巧妙地将创建图片与预加载逻辑分离,并且在未来如果不需要预加载,只要改成请求本体代替请求代理对象就行。

以上就是JavaScript设计模式学习之代理模式的详细内容。

编辑 (opens new window)
#设计模式
上次更新: 2025/04/18, 01:42:12
单例模式
事件代理(事件委托)

← 单例模式 事件代理(事件委托)→

最近更新
01
GSAP动画库——如何高效写动画
04-17
02
自适应方案PxToRem
09-10
03
性能优化-requestAnimationFrame
08-10
更多文章>
Theme by Vdoing | Copyright © 2019-2025 备案号:京ICP备19058102号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式