代理 模式

Posted 沿着路走到底

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理 模式相关的知识,希望对你有一定的参考价值。

概念

使用者无权访问目标对象

中间加代理,通过代理做授权和控制

示例

假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的

UML类图

代码演示 

```js
class ReadImg 
    constructor(fileName) 
        this.fileName = fileName
        this.loadFromDisk()  // 初始化即从硬盘中加载
    
    display() 
        console.log(`display...` + this.fileName)
    
    loadFromDisk() 
        console.log(`loading... ` + this.fileName)
    


class ProxyImg 
    constructor(fileName) 
        this.realImg = new ReadImg(fileName)
    
    display() 
        this.realImg.display()
    


// 测试代码
let proxImg = new ProxyImg('1.png')
proxImg.display()
```

关键在于两者都必须用`display`这一个 API 名字,就像你用不用科学上网,访问`youtube.com`的网站都是一样的。

使用场景

网页事件代理

将目标元素的点击事件,代理到父元素上,以实现某种功能,很常用。

<div id="div1">
    <a href="#">a1</a>
    <a href="#">a2</a>
    <a href="#">a3</a>
    <a href="#">a4</a>
</div>
<button>点击增加一个 a 标签</button>

<script>
    var div1 = document.getElementById('div1')
    div1.addEventListener('click', function (e) 
        var target = e.target
        if (e.nodeName === 'A') 
            alert(target.innerhtml)
        
    )
</script>

jQuery $.proxy

```js
$('#div1').click(function () 
    // this 符合期望
    $(this).addClass('red')
)
$('#div1').click(function () 
    setTimeout(function () 
        // this 不符合期望
        $(this).addClass('red')
    , 1000);
);

// 可以用如下方式解决
$('#div1').click(function () 
    var _this = this
    setTimeout(function () 
        // _this 符合期望
        $(_this).addClass('red')
    , 1000);
);

// 但推荐使用 $.proxy 解决,这样就少定义一个变量
$('#div1').click(function () 
    setTimeout($.proxy(function () 
        // this 符合期望
        $(this).addClass('red')
    , this), 1000);
);
```

总结一下,`$.proxy(fn, obj)`返回的就是`fn`的代理,这个代理和`fn`的功能一样,只不过将`this`设置成了我们期望值。虽然看似简单、常用的功能,但是用代理模式设计的。

ES6 Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。就是一个属性的代理器。

// 明星
let star = 
    name: '张XX',
    age: 25,
    phone: '13910733521'


// 经纪人
let agent = new Proxy(star, 
    get: function (target, key) 
        if (key === 'phone') 
            // 返回经纪人自己的手机号
            return '18611112222'
        
        if (key === 'price') 
            // 明星不报价,经纪人报价
            return 120000
        
        return target[key]
    ,
    set: function (target, key, val) 
        if (key === 'customPrice') 
            if (val < 100000) 
                // 最低 10w
                throw new Error('价格太低')
             else 
                target[key] = val
                return true
            
        
    
)

// 主办方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)

// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000
// agent.customPrice = 90000  // 报错:价格太低
console.log('customPrice', agent.customPrice)

对比:

- vs 适配器模式:

    - 适配器模式:提供一个不同的接口(如不同版本的插头)

    - 代理模式:提供一模一样的接口,用不用代理,访问 facebook 的网址都一样

- vs 装饰器模式

    - 装饰器模式:扩展功能,原有功能不变且可直接使用;使用方也可直接使用目标接口。

    - 代理模式:显示原有功能,提供给使用方的是经过限制或者阉割之后的功能;使用方不可直接使用目标接口。

1

以上是关于代理 模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式代理模式 ( 代理模式结构 | 客户端 | 主题对象 | 被代理对象 | 代理对象 )

代理的模式和原理(代理的模式有几种)

设计模式——代理模式

设计模式-代理模式

设计模式 结构型模式 -- 代理模式(动态代理(CGLIB动态代理)三种代理的对比(静态代理动态代理(JDK代理和CGLIB代理)优缺点使用场景))

代理模式 (ProxyPattern)