# 代理模式

# 介绍

  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制

# 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

# 场景

  • 网页事件代理
<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
  • 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
  • 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

# 设计原则验证

代理类和目标类分离,将目标类与使用者隔离开,符合开放封闭原则

# 附:代理模式、适配器模式、装饰器模式对比

# 代理模式 VS 适配器模式

  • 适配器模式:提供一个不同的接口,旧的无法使用,需要进行转换(如不同版本的插头)
  • 代理模式:提供一模一样的接口(使用者无权使用目标类,通过一个代理,来访问到目标类的效果)

# 代理模式 VS 装饰器模式

  • 装饰器模式:扩展功能,原有功能不变且可直接使用
  • 代理模式:显示原有功能,但是经过限制或者阉割之后的(哪些可以访问,哪些不可以访问,有一定限制)
Last Updated: 12/9/2019, 10:53:44 PM