放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 技术汇总

    • 技术总结
    • 技术文章
  • 技术术语

  • 技术方案

    • 技术场景汇总
    • 技术方案

    • 前端方案

    • 三方平台

    • 图片方案

    • 文件方案

  • 技术点

  • 设计模式及原则

    • 设计模式
    • 创建型模式

    • 结构型模式

      • 装饰器模式
      • 适配器模式
      • 代理模式
        • 代理模式
          • 代理模式分类
          • 模式结构
          • 优点和缺点
        • 代理模式的应用场景
          • 1.事件代理
          • 2.缓存代理
          • 3.虚拟代理
          • 4.保护代理
          • 5.其它代理
      • 外观模式
    • 行为型模式

    • 设计原则
  • technology
放肆青春
2021-12-22

代理模式

# 代理模式

代理模式(Proxy Pattern) 是指为一个原对象找一个代理对象,以便对原对象进行访问。即在访问者与目标对象之间加一层代理,通过代理做授权和控制。代理模式的英文叫做 Proxy 或 Surrogate,它是一种对象结构型模式。

最常见的例子就是经纪人代理明星业务,假设你作为投资人,想联系明星打广告,那么你就需要先经过代理经纪人,经纪人对你的资质进行考察,并为你进行排期,替明星过滤不必要的信息。

事件委托/代理、jQuery 的 $.proxy、ES6 的 proxy 都是这一模式的实现。

# 代理模式分类

代理模式又分为 静态代理 和 动态代理:

  1. 静态代理 是由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的 .class 文件就已经存在了。

  2. 动态代理 是在程序运行时,通过运用反射机制动态的创建而成。

# 模式结构

代理模式包含如下角色:

  • Subject(抽象主题角色):声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
  • Proxy(代理主题角色):也称为委托角色或者被代理角色。定义了代理对象所代表的目标对象。
  • RealSubject(真实主题角色):也叫委托类、代理类。代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

# 优点和缺点

代理模式的优点

  • 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。

  • 远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

  • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。

  • 保护代理可以控制对真实对象的使用权限。

代理模式的缺点

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

# 代理模式的应用场景

# 1.事件代理

事件本身具有“冒泡”的特性,当我们点击子元素时,点击事件会“冒泡”到父元素 div 上,从而被监听到。如此一来,点击事件的监听函数只需要在 父元素 div 元素上被绑定一次即可,而不需要在子元素上被绑定 N 次——这种做法就是事件代理,它可以很大程度上提高我们代码的性能。

// 获取父元素
const father = document.getElementById("father");

// 给父元素安装一次监听函数
father.addEventListener("click", function(e) {
  // 识别是否是目标子元素
  if (e.target.tagName === "A") {
    // 以下是监听函数的函数体
    e.preventDefault();
    alert(`我是${e.target.innerText}`);
  }
});
1
2
3
4
5
6
7
8
9
10
11
12

在这种做法下,我们的点击操作并不会直接触及目标子元素,而是由父元素对事件进行处理和分发、间接地将其作用于子元素,因此这种操作从模式上划分属于代理模式。

# 2.缓存代理

缓存代理比较好理解,它应用于一些计算量较大的场景里。在这种场景下,我们需要“用空间换时间”——当我们需要用到某个已经计算过的值的时候,不想再耗时进行二次计算,而是希望能从内存里去取出现成的计算结果。这种场景下,就需要一个代理来帮我们在进行计算的同时,进行计算结果的缓存了。

应用场景 1:阶乘

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

// 1. 阶乘(专注于自身职责,阶乘,缓存由代理实现)
function factorial(n) {
  console.log("重新计算阶乘");
  if (n < 2) {
    return n;
  } else {
    return n * factorial(n - 1);
  }
}

function proxy(fn) {
  const catchObject = {};

  return function(key) {
    if (key in catchObject) {
      return catchObject[key];
    } else {
      return (catchObject[key] = fn(key));
    }
  };
}

const instance = proxy(factorial);
instance(3);
instance(3);
instance(3);

//这时候我们发现无论 “重复” 执行多少次, 都只计算了一次
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

应用场景 2:tab 切换

  <div class="tab" onClick="handleClick">
        <span> 1 </span>
        <span> 2 </span>
        <span> 3 </span>
    </div>
  <div class="content">
      <!-- 根据tab获取不同数据显示在这 -->
  </div>

  class ProxyTab {
      static catch = {}
      constructor(target) {
          if (!ProxyTab.catch[target]) {
              ProxyTab.catch[target] = this.http()
          }
      }
      http() {
          return axios.get('xxx')
      }
  }

  function handleClick(e) {
      new ProxyTab(e.target)
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 3.虚拟代理

将一些代价昂贵的操作放置在代理对象中,待到机会合适时再进行,这种代理就叫虚拟代理

应用场景 :图片懒加载

在 Web 开发中,图片预加载是一种常用的技术,如果直接给某个 img 标签节点设置 src 属性,

由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法是先用一张

loading 图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到 img 节点里,这种场景就很适合使用虚拟代理。

虚拟代理:作为创建开销大的对象的代表;虚拟代理经常直到我们真正需要一个对象的时候才创建它;当对象在创建或创建中时,由虚拟代理来扮演对象的替身;对象创建后,代理就会将请求直接委托给对象。

const image = (function() {
  const imgNode = document.createElement("img");

  document.body.appendChild(imgNode);

  return {
    setSrc: function(src) {
      imgNode.src = src;
    },
  };
})();

// 代理容器
const proxyImage = (function() {
  let img = new Image();

  // 加载完之后将设置为添加的图片
  img.onload = function() {
    image.setSrc(this.src);
  };

  return {
    setSrc: function(src) {
      image.setSrc("loading.gif");
      img.src = src;
    },
  };
})();

proxyImage.setSrc("file.jpg");
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

代理容器控制了客户对 Image 的访问,并且在过程中加了一些额外的操作。

# 4.保护代理

在代理模式中,替身对象能做到过滤一些对本体不合理的请求时,这种代理就叫保护代理

// 保护代理
function Flower() {}
function Person(name, age, salary) {
  this.age = age;
  this.name = name;
  this.salary = salary;
}
Person.prototype.sendFlower = function(target, person) {
  var flower = new Flower();
  target.receive(flower, person);
};
var person1 = new Person("www", 20, 4000);
var person2 = new Person("AAA", 25, 8000);
var person3 = new Person("BBB", 45, 16000);

var proxyObj = {
  receive: function(flower, person) {
    if (person.age >= 40) {
      console.log(person.name + ",你年龄太大了");
      return false;
    }
    if (person.salary < 5000) {
      console.log(person.name + ",你工资太低了");
      return false;
    }
    originObj.receive(flower);
    console.log(person.name + ",恭喜你,女神收下了你的花");
  },
};
var originObj = {
  receive: function(flower) {},
};
person1.sendFlower(proxyObj, person1); // 输出www,你工资太低了
person2.sendFlower(proxyObj, person2); // 输出AAA,恭喜你,女神收下了你的花
person3.sendFlower(proxyObj, person3); // 输出BBB,你年龄太大了
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

参考:前端 JS 高频面试题---3.代理模式 (opens new window)

学习 JavaScript 设计模式 - 代理模式 (opens new window)

# 5.其它代理

代理模式的变体种类非常多,限于篇幅及其在 JavaScript 中的适用性,本章只简约介绍一下这些代理,就不一一详细展开说明了。

  1. 防火墙代理:控制网络资源的访问,保护主题不让“坏人”接近。

  2. 远程代理:为一个对象在不同的地址空间提供局部代表,在 Java 中,远程代理可以是另一个虚拟机中的对象。

  3. 智能引用代理:取代了简单的指针,它在访问对象时执行一些附加操作,比如计算一个对象被引用的次数。

  4. 写时复制代理:通常用于复制一个庞大对象的情况。写时复制代理延迟了复制的过程,当对象被真正修改时,才对它进行复制操作。写时复制代理是虚拟代理的一种变体,DLL(操作系统中的动态链接库)是其典型运用场景。

更新时间: 12/22/2021, 6:20:36 PM
适配器模式
外观模式

← 适配器模式 外观模式→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式