前端必须 懂的设计模式-署理 模式

[复制链接]
查看374 | 回复1 | 2022-11-19 18:43:48 | 显示全部楼层 |阅读模式
署理 模式

署理 模式 (Proxy Pattern)又称委托模式,它为目标对象创造  了一个署理 对象,以控制对目标对象的拜访 ,也可以理解为对外裸露 的接口并不是原对象。通俗地讲,生活中也有比较  常见的署理 模式:中介、寄卖、经纪人等等。而这种模式存在的意义在于当拜访 者与被拜访 者不便利 直接拜访 /接触的情况下,提供一个替身来处理  事务流程,实际拜访 的是替身,替身将事务做了一些处理  /过滤之后,再转交给本体对象以减轻本体对象的累赘 。
常见署理 模式​


  • 掩护 署理
  • 虚拟署理
  • 缓存署理
  • 。。。
实现​

掩护 署理 :
  /**  * 掩护 署理 简单实现  * client向办事 端发送一个请求  * proxy署理 请求转发给办事 端  * 办事 端处理  请求  */  // 改进  前  const Request = function () {};    const client = {   requestTo: (server) => {     const req = new Request();     server.receiveRequest(req);    },  };    const server = {   handleRequest: (request) => {     console.log('receive request: ', request);    },  };    const proxy = {   receiveRequest: (request) => {     console.log('proxy request: ', request);     server.handleRequest(request);    },  };    client.requestTo(proxy);  // 改进  后  const proxy = {   receiveRequest: (request) => {     // 校验身份     const pass = validatePassport(request);     if (pass) {       // 监听办事 端 ready 后署理 请求       server.listenReady(() => {         console.log('proxy request: ', request);         server.handleRequest(request);       });     }    },  };虚拟署理 :虚拟署理 是把一些开销很年夜 的对象或者办法 ,延迟到真正需要它的时候才去创建  执行
  // 图片懒加载  const img = (() => {    const imgNode = document.createElement('img');    imgNode.style.width = '200px'    document.body.appendChild(imgNode);    return {      setSrc: (src) => {        imgNode.src = src;      },      setLoading: () => {        imgNode.src = './img/loading.gif'      }    };  })();  const proxyImg = ((source) => {    // 替身图片对象    const tempImg = new Image();    // 监听资源加载完成,将资源替换给实体图片对象    tempImg.onload = function () {      source.setSrc(this.src);    };    return {      // 署理 开始将实体对象设置为loading状态,使用替身对象开始加载图片资源      setSrc:(src)=>{        source.setLoading()        tempImg.src = src;      }    }  })(img);  proxyImg.setSrc('https://static-prod.retech.us/onder-cender/DoorDash.svg')  // ------------------------------------------------------------  // 归并 http请求  //上传请求  let upload = function(ids){      $.ajax({          data: {              id:ids          }      })  }  //署理 归并 请求  let proxy = (function(){    let cache = [],      timer = null;    return function(id){      cache[cache.length] = id;      if(timer) return false;      timer = setTimeout(function(){        upload(cache.join(','));        clearTimeout(timer);        timer = null;        cache = [];      },2000);    }      })();  // 绑定点击事件  let checkbox = document.getElementsByTagName( "input" );  for(var i= 0, c; c = checkbox[i++];){    c.onclick = function(){      if(this.checked === true){        proxy(this.id);      }    }  }缓存署理 :缓存署理 可以作为一些开销年夜 的运算结果提供暂时的存储,下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果
  /**  * 对于一些比较  消耗性能的操作  * 可以将结果缓存起来  * 在获取结果时优先从缓存中取,缓存中没有再计算  */  let fibonacci = function(n){    if(n === 1 || n === 0 ) return n;    return fibonacci(n-1) + fibonacci(n-2);  }  //缓存署理   let proxy = (function(fn){    let cache = {};    return function(){      let args = Array.prototype.join.call(arguments,',');      if(args in cache){        return cache[args];      }      return cache[args] = fn.apply(this,arguments);    }  })(fibonacci);  proxy(3)实际案例​

Vue中的署理 模式:
  // 将数据、办法 、计算属性等署理 到组件实例上  let vm = new Vue({   data: {     msg: 'hello',     vue: 'vue'    },   computed:{     helloVue(){       return this.msg + ' ' + this.vue     }    },   mounted(){     console.log(this.helloVue)    }  })源码剖析 :
export function proxy (target: Object, sourceKey: string, key: string) {  sharedPropertyDefinition.get = function proxyGetter () {    return this[sourceKey][key]  }  sharedPropertyDefinition.set = function proxySetter (val) {    this[sourceKey][key] = val  }  Object.defineProperty(target, key, sharedPropertyDefinition)}export function initState (vm: Component) {  vm._watchers = []  const opts = vm.$options  if (opts.props) initProps(vm, opts.props)  if (opts.methods) initMethods(vm, opts.methods)  if (opts.data) {    initData(vm)  } else {    observe(vm._data = {}, true /* asRootData */)  }   if (opts.computed) initComputed(vm, opts.computed)  if (opts.watch && opts.watch !== nativeWatch) {    initWatch(vm, opts.watch)  }}function initData (vm: Component) {  let data = vm.$options.data  // 初始化 _data,组件中 data 是函数,挪用 函数返回结果  // 不然 直接返回 data  data = vm._data = typeof data === 'function'    ? getData(data, vm)    : data || {}  if (!isPlainObject(data)) {    data = {}    process.env.NODE_ENV !== 'production' && warn(      'data functions should return an object:\n' +      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',      vm    )  }  // proxy data on instance  // 获取 data 中的所有属性  const keys = Object.keys(data)  // 获取 props / methods  const props = vm.$options.props  const methods = vm.$options.methods  let i = keys.length  // 判断 data 上的成员是否和  props/methods 重名  while (i--) {    const key = keys    if (process.env.NODE_ENV !== 'production') {      if (methods && hasOwn(methods, key)) {        warn(          `Method "${key}" has already been defined as a data property.`,          vm        )      }    }    if (props && hasOwn(props, key)) {      process.env.NODE_ENV !== 'production' && warn(        `The data property "${key}" is already declared as a prop. ` +        `Use prop default value instead.`,        vm      )    } else if (!isReserved(key)) {      proxy(vm, `_data`, key)    }  }  // observe data  // 响应式处理    observe(data, true /* asRootData */)}总结​

在面向对象的编程中,署理 模式的合理使用能够很好地体现下面两条设计原则:

  • 单一职责原则: 面向对象设计中勉励 将不合  的职责散布 到细粒度的对象中,Proxy 在原对象的基础上进行了功能  的衍生而又不影响原对象,相符 松耦合高内聚的设计理念。
  • 开放-封闭  原则:代码可以随时从法度模范   中去失落 ,而不消 对其他部分  的代码进行修改,在实际场景中,随着版本的迭代可能会有多种原因不再需要署理 ,那么就可以容易的将署理 对象换成原对象的挪用
对于署理 模式 Proxy 作用主要体现在三个方面:

  • 拦截和监视外部对对象的拜访
  • 降低对象的庞杂 度
  • 在庞杂 操作前对操作进行校验或对所需资源进行治理
回复

使用道具 举报

黎落苏小亮落t | 2022-11-19 18:44:36 | 显示全部楼层
转发了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

16

主题

52

回帖

162

积分

注册会员

Rank: 2

积分
162