乐趣区

关于编程:设计模式代理模式

代理模式这个设计模式对我来说有非凡的意义,因为这是我在工作中第一次分享学习的主题,过后我还是一个实习生,当初一眨眼曾经过来很多年了。

设计模式是什么

过后分享的具体内容是什么我曾经不记得了,而且其实我过后也并不太了解设计模式是什么,起初浏览了一些文章,我模摸糊糊地了解设计模式就是代码的设计方案。

说到这,我想起之前看的《黑客与画家》,外面说优良的程序员更像画家,这么一来不就对上了吗,两者关注的都是如何设计,是创造者,画家留神的是如何去设计构图,程序员留神的是如何去设计数据结构、代码构造、零碎架构,一份设计良好的程序代码具备更好的可读性和可维护性,所以设计模式就是一些通过测验的、通用的、可复用的代码设计方案。

设计模式分类

wiki 中将设计模式分为四类,别离是:

  • 创立模式(creational patterns)
  • 构造模式(structural patterns)
  • 行为模式(behavioral patterns)
  • 并发模式(concurrency patterns)

代理模式属于其中的构造模式。

代理

说到代理,咱们能够将其对应到一个很生活化的词汇——中介,比方房产中介、留学中介等等一些中介机构,就是本来要间接建设关系的单方 a 和 b 之间多了一个中间人 c,这个 c 就是代理;甚至咱们能够就从字面上了解,代理作为动词是代为解决,作为名词就是代为解决的机构;代理能够为 a 解决事件,也能够为 b 解决事件。

当咱们的代码中减少了具备代理性能的角色,就能够认为其利用了代理模式。比方 ES6 中新增的 Proxy

// 假如存在一个对象 a
let a = {name: '鸡蛋'}
// 然而我不心愿代码里的其余局部对 a 间接进行拜访
// 此时咱们就能够创立一个 a 的代理,来解决其余内容对 a 的拜访
let aProxy = new Proxy(a, {get: function (a, key) {return Reflect.get(a, key);
  } 
});

生存情境

那么什么状况下会应用到代理呢?以下列举我想到的一些生存情境:

第一个,a 想要与 b 建设关系,然而没有渠道、分割不上,刚好 c 能够接触到 b,c 就能够替 a 去分割 b

第二个,a 想要与 b 分割,然而又不想 b 晓得本人,也能够应用代理 c 代替本人与 b 分割

第三个,a 想要去 b 国留学,然而除了提交申请,对其余的流程不甚了解,就能够通过中介机构 c 提交申请并解决其余事宜

第四个,b 作为一个重要资源,a 不能轻易拜访,须要通过 b 的代理 c 来校验 a 的身份和权限,通过验证后 c 能够将资源 b 中合乎 a 权限范畴的内容展现给 a

总结一下,代理在上述情境中起到的作用大抵是:

  • 建设渠道
  • 爱护信息
  • 解决额定事项

解决的问题

当初咱们来看 wiki 中形容的代理模式所解决的问题:

What problems can the Proxy design pattern solve?

  • The access to an object should be controlled.
  • Additional functionality should be provided when accessing an object.

When accessing sensitive objects, for example, it should be possible to check that clients have the needed access rights.

翻译过去大略是以下意思:

  • 对受控对象的拜访
  • 拜访对象时应提供附加的性能

怎么做

那么软件设计中的代理模式具体是怎么做的呢?wiki 也给出了形容:

Define a separate Proxy object that

  • can be used as substitute for another object (Subject) and
  • implements additional functionality to control the access to this subject.

This makes it possible to work through a Proxy object to perform additional functionality when accessing a subject. For example, to check the access rights of clients accessing a sensitive object.

To act as substitute for a subject, a proxy must implement the Subject interface. Clients can’t tell whether they work with a subject or its proxy.

翻译过去大略是以下意思:

定义一个独自的代理对象

  • 可用于代替另一个对象(主体)
  • 并实现额定性能,以管制对该主体的拜访。

这样就能够通过代理对象在拜访主体时执行附加性能。例如,查看拜访敏感对象的客户端的拜访权限。

要代替主体,代理必须实现主体接口。客户无奈分辨他们是在与主体还是其代理一起工作。

利用场景

既然设计模式是通用的解决方案,那必然有其利用场景。

1. wiki

以下是 wiki 给出的代理模式三个可能的利用场景

近程代理

在分布式对象通信中,本地对象代表近程对象(属于不同地址空间的对象)。本地对象是近程对象的代理,对本地对象的办法调用会导致对近程对象的近程办法调用。一个例子是主动取款机的实现,主动取款机可能持有近程服务器中银行信息的代理对象。

虚构代理

在某些状况下,骨架示意可能比简单或轻便的对象更有劣势。当底层图像体积宏大时,能够应用虚构代理对象来示意,并依据须要加载实在对象。

爱护代理

爱护代理可用于依据拜访权限 管制对资源的拜访。

2. 前端利用

那在前端有哪些场景能够利用代理模式呢?

虚构代理

首先就是能够将虚构代理利用在图片懒加载,这也是性能优化的一种伎俩。

在图片较大或者较多的状况下(列表)利用虚构代理,具体操作就是,应用占位元素代替图片渲染,期待图片加载结束或进入可视区域后,再进行实在图片的渲染。这里就是用占位元素作为实在图片的代理,以管制在图片未加载实现时如何去解决其渲染。

事件代理

比方利用事件冒泡,将事件监听器搁置在更下级的元素,来实现事件代理。

咱们晓得 DOM 事件流有三个阶段:事件捕捉 => 达到指标 => 事件冒泡,当咱们想解决某个指标元素上的事件,能够在事件流达到指标元素时解决,也能够在事件流从指标元素冒泡到更下级的元素时进行解决。

应用事件代理,就相当于更下级的元素代替指标元素去处理事件,而不是指标元素间接去处理事件。

这在一些状况下,能够进步代码的性能。比方,要监听 li 上的点击事件:

<ul id="father">
        <li><a href="#"> 链接 1 号 </a></li>
        <li><a href="#"> 链接 2 号 </a></li>
        <li><a href="#"> 链接 3 号 </a></li>
        <li><a href="#"> 链接 4 号 </a></li>
        <li><a href="#"> 链接 5 号 </a></li>
        <li><a href="#"> 链接 6 号 </a></li>
</div>

如果咱们给每个 li 都设置监听器,那至多要加 6 个监听器,如果标签进一步增多,那么性能开销会加大;而如果 li 反对动静增加,那就须要每减少一个 li 就得绑定一次事件。

此时应用事件代理就能够很大水平上晋升代码的性能,只须要在 ul 上绑定一次事件就足矣;而且通常在列表中,点击每个列表项的事件处理逻辑往往差不多,只需在事件处理程序中应用 id 之类的属性对 li 进行辨别即可。

再比方接口申请事件,前端如果应用 axios 申请接口,能够在 axios 的拦截器中先去校验本地是否存在 token 等认证信息,此时能够把这个 axios 看作一个代理,它代替咱们去解决申请事件,在帮咱们做了一系列校验以及格局解决等操作后,才会发动申请。

爱护代理

也是对资源的访问控制,比方前端路由跳转,能够在路由守卫中做校验,是否具备指标路由的拜访权限,如果有权限,能力进行跳转,此时能够把路由守卫看作一个代理。

以上能够看作是对指标对象(指标路由)的爱护。

另外咱们也能够应用 ES6 中的 Proxy 来代理实在的对象,以避免实在对象被意外拜访或批改,当然也能够在通过代理对象来拜访实在对象时,做一些额定的操作。

缓存代理

在一些场景下,咱们能够把缓存也当作一种代理,比方 vue 中的计算属性,计算属性通常是依据一般属性计算而来,在一般属性没有更新的状况下也去计算,就有点节约性能了,所以计算属性将最近一次的计算结果进行缓存,在没有更新的状况下,就能够将这个计算结果当做计算属性的一个代理。

总结

应用代理模式能够达到增强管制、晋升性能、优化代码构造等成果。

之所以它在分类中属于构造模式,也很好了解,就是在 a 和 b 之间多了一个 c,代码构造产生了变动,但 a 和 b 的行为都没有变,并且没有创立新的对象,c 属于媒介而不是对象。

参考资料

wiki: Software_design_pattern

wiki: Proxy pattern

退出移动版