[JS设计模式]代理模式

302 阅读3分钟

前言

今天我们来看一下代理模式,代理模式其实在前端中的使用频率是非常高的。只是可能大部分的开发者并没有感知到。我们很多时候会为了减少直接对dom的操作次数,会先用一个对象实例来反映我们的操作,最后再修改dom。其实这里就可以认为对象实例就是dom实例的代理了。

说明

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

设计思路

代理模式核心解决的应该是让对象功能更单一。举个例子,现在公司的老板有个接受信息的接口,那么假如我们需要给老板发送消息,操作应该如下:

const boss = {
  getMsg(msg){
    // 处理消息
  }
};

boss.getMsg({
  // 消息内容
});

但事实上我们发送给老板的信息,可能会非常复杂甚至出现虚假无用信息,老板需要花很多时间来处理阅读。众所周知老板的时间是非常宝贵的,因此一般他会请一个秘书来帮忙收集信息,让后由秘书来整理汇报。由此,我们来修改一下现有的代码。

const boss = {
  getMsg(msg){
    // 处理消息
  }
};

const secretary = {
  getMsg(msg){
    // 处理消息
    const newMsg = handle(msg);
    boos.getMsg(newMsg);
  }
};

secretary.getMsg({
  // 消息内容
});

现在上方修改后的代码,就是代理模式的结构了。大家可以发现,我们从直接给老板发信息,变成了先给秘书发信息,秘书处理过后,再由秘书给老板发送信息。

这样的变化可以带来以下的好处:

  1. 老板的getMsg功能可以变得更加单一,不需要加太多的对信息的处理。
  2. 由秘书代理老板之后,秘书可以对信息作更多细节处理。

代理模式的种类

代理模式可以根据代理所实现的功能分成多个种类。

保护代理

保护代理主要是指,代理实例尽可能地保证目标实例的功能正常。因此通常代理会做一些像数据筛选,格式整理等功能。

const secretary = {
  getMsg(msg){
    // ...只把紧急认为给老板
    if(msg.priority !== 'hight' ){
      boos.getMsg(msg);
    }
  }
};

虚拟代理

虚拟代理一般是指,把某些大开销的操作放在合适的时候执行。

const secretary = {
  getMsg(msg){
    boss.listenMood(function(){
      //	假如这里是一个大开销的操作
      const task =  new Task();
      boos.getMsg(task);
    })
  }
};

缓存代理

缓存代理就很好理解了,就是在代理中加一层缓存。这里假设每次给老板发了信息之后,都会有回复。秘书就可以把老板的回复缓存起来,下次如果有客户问到同样的问题,秘书就可以直接把上次老板的回复给他。

const secretary = {
  answers:{},
  getMsg(msg){
    if(this.answers[mgs]){
     return this.answers[mgs];
    }else{
      const answer = boss.getMsg(msg);
      this.answers[mgs] = answer;
    }
  }
};

更多

代理模式可以实现的功能当然不仅仅只有这3种,还要其他像,防火墙代理,远程代理,智能引用代理等。有兴趣的朋友可以自行查阅。

总结

相信大部分的开发者看到这里都能发现,其实自己过去写的代码里或多或少都用到了代理模式的思想。因为代理模式本身就是一种非常通用的结构。希望大家在阅读完这篇文章之后,可以回顾一下自己写过的相似代码。思想一下有没有进一步优化的空间。

参考

《JavaScript设计模式与开发实践》—— 曾探