# 代理模式
# 介绍
- 使用者无权访问目标对象
- 中间加代理,通过代理做授权和控制
# UML类图
# 代码演示
class ReadImg {
constructor(fileName) {
this.fileName = fileName
this.loadFromDisk() // 初始化即从硬盘中加载
}
loadFromDisk() {
console.log('loading...',this.fileName)
}
display() {
console.log('display...',this.fileName)
}
}
// 代理
class ProxyImg {
constructor(fileName) {
this.realImg = new ReadImg(fileName)
}
display() {
this.realImg.display()
}
}
// Test
let proxyImg = new ProxyImg('1.png')
proxyImg.display()
/*
Result:
loading...1.png
display...1.png
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 场景
- 网页事件代理
<div id='div1'>
<a href='#'>a1</a>
<a href='#'>a2</a>
<a href='#'>a3</a>
<a href='#'>a4</a>
</div>
<script>
var div1 = document.getElementById('div1')
div1.addEventListener('click',function(e) {
var target = e.target
if(target.nodeName === 'A'){
alert(target.innerHtml)
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- JQuery $.proxy
$('#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)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- ES6 Proxy
// 明星 & 经纪人 案例
// 顾客要聘请明星,不能直接与明星接触,而是与明星经纪人接触
// 明星
let star = {
name: '张三',
age: 20,
phone: '13000000000'
}
// 经纪人
let agent = new Proxy( star, {
get: function(target, key){
if(key === 'phone'){
// 返回经纪人自己的手机号
return '10086'
}
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
}
}
}
})
// Test
console.log(agent.name) // 张三
console.log(agent.age) // 20
console.log(agent.phone) // 10086
console.log(agent.price) // 120000
agent.customPrice = 80000 // 抛错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 设计原则验证
代理类和目标类分离,将目标类与使用者隔离开,符合开放封闭原则
# 附:代理模式、适配器模式、装饰器模式对比
# 代理模式 VS 适配器模式
- 适配器模式:提供一个不同的接口,旧的无法使用,需要进行转换(如不同版本的插头)
- 代理模式:提供一模一样的接口(使用者无权使用目标类,通过一个代理,来访问到目标类的效果)
# 代理模式 VS 装饰器模式
- 装饰器模式:扩展功能,原有功能不变且可直接使用
- 代理模式:显示原有功能,但是经过限制或者阉割之后的(哪些可以访问,哪些不可以访问,有一定限制)