代理 模式
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代理)优缺点使用场景))