最近离职在家,闲了好几天,复习一下代理模式。

定义

给某一个对象提供一个代理对象,并有代理对象控制原对象的引用。属于结构型模式。

结构

UML 类图

由上图可以分析出构造一个代理模式需要三个类:

  • Subject:抽象类;
  • Proxy:代理类;
  • RealSubject:实际类;
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
class Subject {
constructor () {}
request () {
console.error('请重写 request 方法!')
}
}
class Proxy extends Subject {
constructor () {
super()
}
afterRequest () {}
beforeRequest () {}
request () {}
}
class RealSubject extends Subject {
constructor () {
super()
}
request () {}
}

时序图

通过时序图,我们可以了解到 用户(:Client)是直接交互 Proxy 类的实例的。所以我们按照时序图中的 1.0 - 1.5 顺序去具体实现 UML 图的三个类。

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
44
45
class Subject {
constructor () {}
request () {
console.error('请重写 request 方法!')
}
}
class Proxy extends Subject {
constructor () {
super()
this.realSubject = new RealSubject()
}
afterRequest () {
console.log('request end')
}
beforeRequest () {
console.log('request start')
}
request () {
this.beforeRequest()
this.realSubject.request()
this.afterRequest()
}
}
class RealSubject extends Subject {
constructor () {
super()
}
request () {
console.log('requesting')
}
}
let proxy = new Proxy()
proxy.request()
// "request start"
// "requesting"
// "request end"

这样我们就可以实现一个 代理模式啦 🙃

当然实际项目中可能没有这么简单,也许在访问真实对象之前需要发送一个异步请求 或者 真实对象的请求是个异步对象,这样我们就需要加上一些异步处理了。

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
class Proxy extends Subject {
constructor () {
super()
this.realSubject = new RealSubject()
}
afterRequest () {
console.log('request end')
}
beforeRequest () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('request start, sleep 1000')
resolve()
}, 1000)
})
}
request () {
(async function (_this) {
await _this.beforeRequest()
await _this.realSubject.request()
await _this.afterRequest()
})(this)
}
}

这只是一个简单的示例,具体的实现依据业务实际的需求进行改写。

图片懒加载

web 上对于代理模式的实现,懒加载是最好的体现了。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class ImgSubject {
constructor (node, imgUrl) {
this.node = node
this.imgUrl = imgUrl
}
request () {
console.error('请重写 request 方法')
}
}
class RealImgSubject extends ImgSubject {
constructor (node, imgUrl) {
super(node, imgUrl)
}
request () {
this.node.src = this.imgUrl
console.log(this.node.src)
}
}
class ImgProxy extends ImgSubject {
constructor (node, imgUrl, loadSrc) {
super(node, imgUrl)
this.loadSrc = loadSrc
this.realImg = new RealImgSubject(node, imgUrl)
}
beforeRequest () {
// 先加载较小的 loading 图片
this.node.src = this.loadSrc
return new Promise((resolve, reject) => {
let fakeImgNode = document.createElement('img')
fakeImgNode.src = this.imgUrl
fakeImgNode.onload = () => {
resolve()
}
})
}
afterRequest () {
console.log('其实没我什么事...')
}
request () {
(async function (_this) {
await _this.beforeRequest()
await _this.realImg.request()
await _this.afterRequest()
})(this)
}
}
let node = document.querySelector('#testImg')
let proxy = new ImgProxy(
node,
'https://www.google.com/logos/doodles/2017/esther-afua-ocloos-98th-birthday-5995813305057280-l.png',
'http://img.lanrentuku.com/img/allimg/1212/5-121204193Q8.gif'
)
console.log(proxy)
proxy.request()

以上就是一个简单的图片懒加载的实现。当然代理模式的使用场景是非常多的。代理模式的优点在于

  • 代理模式能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。
  • 远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
  • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。
  • 保护代理可以控制对真实对象的使用权限。

以上就是我对代理模式的学习啦 ~ 😎


图解代理模式