设计模式——代理模式

82 阅读2分钟

代理模式:为一个对象提供代用品或者占位符,以便控制对它的访问;应与实体应保持一致性,暴露同样的接口

代理模式可分虚拟代理、缓存代理、保护代理等,这里主要介绍下虚拟代理和缓存代理。

  1. 虚拟代理:将一个开销很大的任务延迟到真正需要它的时候再去执行

虚拟代理一个很好的例子是图片预加载,如果直接给img标签设置src属性,由于图片过大或者网络不佳,图片的位置往往会出现一段时间空白。可以先使用一张loading图占位,当图片加载好了之后再填充到img里。

// 图片加载
function loadImg() {
  const img = new Image();
  document.body.append(img);
  return  {
    setSrc(src) {
      img.src = src;
    }
  }
}

const remoteSrc = 'https://s.cn.bing.net/th?id=OHR.ChacoCulture_ZH-CN2098865361_1920x1080.webp&qlt=50';
loadImg().setSrc(remoteSrc)

// 虚拟代理方式
function proxyLoadImg() {
  const img = new Image();
  img.onload = () => {
    realImg.setSrc(img.src)
  }
  const realImg = loadImg();
  return {
    setSrc(src) {
      // 先设置loading占位,等图片加载好后再设置
      realImg.setSrc('./loading.gif');
      img.src = src;
    }
  }
}

proxyLoadImg().setSrc(remoteSrc)

其实不使用代理也可以实现,这里引用一下单一职责原则(就一个函数来说,应该仅有一个引起它变化的原因。如果多个职责耦合在一起,这个对象会变得巨大,多个职责耦合在一起,引起变化的原因就会多个)对于给img设置src来说,预加载只是一个锦上添花的功能,如果把这个操作分离开更好。

  1. 缓存代理:将计算结果进行缓存,当下次传入同样的参数时直接从缓存中去取结果,而不用再重新计算
function multi(...args) {
  console.log('run')
  return args.reduce((a, b) => a * b);
}
console.log(multi(1,3,5,7))
console.log(multi(1,3,5,7))

// 通用的缓存代理
function cacheProxy(fn) {
  const cache = {};
  return function(...args) {
    if (!cache[args]) {
      cache[args] = fn.apply(this, args);
    }
    return cache[args]
  }
}

const cacheMulti = cacheProxy(multi);
console.log(cacheMulti(1,3,5,7))
console.log(cacheMulti(1,3,5,7)) // 只计算了一次