美文网首页
设计模式之代理模式

设计模式之代理模式

作者: 颖小李 | 来源:发表于2021-03-04 15:44 被阅读0次

    1.代理模式。在某些情况下,出于种种考虑/限制,一个对象不能直接访问另一个对象,需要一个第三者(代理)牵线搭桥从而间接达到访问目的,这样的模式就是代理模式。
    2.业务开发中最常见的四种代理类型
    (1)事件代理
    用代理模式实现多个子元素的事件监听

    // 获取父元素
    const father = document.getElementById('father')
    
    // 给父元素安装一次监听函数
    father.addEventListener('click', function(e) {
        // 识别是否是目标子元素
        if(e.target.tagName === 'A') {
            // 以下是监听函数的函数体
            e.preventDefault()
            alert(`我是${e.target.innerText}`)
        }
    } )
    

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

    class PreLoadImage {
        constructor(imgNode) {
            // 获取真实的DOM节点
            this.imgNode = imgNode
        }
         
        // 操作img节点的src属性
        setSrc(imgUrl) {
            this.imgNode.src = imgUrl
        }
    }
    
    class ProxyImage {
        // 占位图的url地址
        static LOADING_URL = 'xxxxxx'
    
        constructor(targetImage) {
            // 目标Image,即PreLoadImage实例
            this.targetImage = targetImage
        }
        
        // 该方法主要操作虚拟Image,完成加载
        setSrc(targetUrl) {
           // 真实img节点初始化时展示的是一个占位图
            this.targetImage.setSrc(ProxyImage.LOADING_URL)
            // 创建一个帮我们加载图片的虚拟Image实例
            const virtualImage = new Image()
            // 监听目标图片加载的情况,完成时再将DOM上的真实img节点的src属性设置为目标图片的url
            virtualImage.onload = () => {
                this.targetImage.setSrc(targetUrl)
            }
            // 设置src属性,虚拟Image实例开始加载图片
            virtualImage.src = targetUrl
        }
    }
    

    PreLoadImage 专心去做 DOM 层面的事情(真实 DOM 节点的获取、img 节点的链接设置).
    ProxyImage 帮我们调度了预加载相关的工作,我们可以通过 ProxyImage 这个代理,实现对真实 img 节点的间接访问,并得到我们想要的效果。
    在这个实例中,virtualImage 这个对象是一个“幕后英雄”,它始终存在于 JavaScript 世界中、代替真实 DOM 发起了图片加载请求、完成了图片加载工作,却从未在渲染层面抛头露面。因此这种模式被称为“虚拟代理”模式。
    (3)缓存代理
    应用于一些计算量较大的场景里。在这种场景下,我们需要“用空间换时间”——当我们需要用到某个已经计算过的值的时候,不想再耗时进行二次计算,而是希望能从内存里去取出现成的计算结果。这种场景下,就需要一个代理来帮我们在进行计算的同时,进行计算结果的缓存了。
    (4)保护代理
    Proxy,它本身就是为拦截而生的,所以我们目前实现保护代理时,考虑的首要方案就是 ES6 中的 Proxy。
    Proxy可以理解成,在目标对象之前架设一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

    let obj = new Proxy({},{
      get:function(target,propKey,receiver){
        console.log(`getting ${propKey}!`)
        return Reflect.get(target, propKey, receiver)
      },
      set: function(target, propKey,value,receiver){
        console.log(`setting ${propKey}!`)
        return Reflect.set(target, propKey, value, receiver)
      }
    })
    
    obj.count = 1
    //  setting count!
    console.log(++obj.count)
    //  getting count!
    //  setting count!
    //  2
    

    3.代理模式的目的是十分多样化的,既可以是为了加强控制、拓展功能、提高性能,也可以仅仅是为了优化我们的代码结构、实现功能的解耦。无论是出于什么目的,这种模式的套路就只有一个—— A 不能直接访问 B,A 需要借助一个帮手来访问 B,这个帮手就是代理器。需要代理器出面解决的问题,就是代理模式发光发热的应用场景。

    参考:JavaScript设计模式之代理模式1
    JavaScript设计模式之代理模式2
    阮一峰 proxy

    相关文章

      网友评论

          本文标题:设计模式之代理模式

          本文链接:https://www.haomeiwen.com/subject/xmkkqltx.html