代理模式:通过一个中间对象,控制对真实想要调用对象的访问.

代理模式的用途:

  1. 代理将接受的信息 加工处理后传给本体,还可以控制本体接受数据的速率.
  2. 代理帮助缓存本体已经处理过的数据.
  3. 代理校验是否有权限访问本体.

在前端场景常见的代理模式有:

1. 保护代理: 代理校验访问本体权限,帮本体过滤信息.
 2. 虚拟代理: 代理在本体可以接受信息的时候传递信息给它.
 3. 缓存代理: 缓存处理过的数据,当再次请求时不需要给本体处理.

保护代理

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
// 代理, 校验用户访问权限
class ProxyDoor {
door:{new(): Door};
constructor () {
this.door = new Door;
}
open(pw:string) {
if(this.authenticate(pw)) {
return this.door.open();
} else {
return {status: false,msg: '开门密码错误!'}
}
};
authenticate(pw: string) {
return pw === 'passsord';
}
}

// 本体
class Door {
constructor () {}
open() {
return {
status: true,
msg: '门🚪已打开!'
}
}
}

虚拟代理

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
class LoadImage {
imageNode: HTMLElement;
constructor () {
this.imageNode = document.createElement('img');
document.body.appendChil(imageNode);
}
setSrc (src: string) {
this.imageNode.src = src
}
}

class ProxyLoadImage {
img: Image;
loadImage: {new(): LoadImage};
constructor () {
self = this;
self.img = new Image;
self.loadImage = new LoadImage()
self.img.onload = function () {
self.loadImage.setSrc(this.src)
}
}

setSrc(src: string) {
this.loadImage('./img/xxx.png');
this.img.src = src;
}
}

上面👆这段代码,是前端中最常见的图片预加载.当真实图片没加载完成时,在图片位置上先用本地的小图当占位符.

图片预加载不用代理模式也可以很简单的实现,为什么要用代理模式呢.是因为,面向对象设计原则之一是: 单一职责原则.

单一职责原则:一个类(方法,对象),只有一个因素会引起它的变化.

如果一个类(方法,对象)自身有多个因素会导致它变化,说明它承担的职责太多,这些职责耦合在一起.并不利于它的维护和扩展.

上面的代码中,将预加载和展示图片分离开来.代理负责预加载,本体只负责展示图像.这样代码更清晰,灵活.

缓存代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function mult () {
var a = 1;
for(let i = 0, l = arguments.length; i < l; i++) {
a =a * arguments[i];
};
return a;
}

proxMult = (function () {
var catchValue: {[key:string]: number}= {};
return function () {
let key = Array.prototype.join.call(arguments,',');
if (key in catchValue) {
return catchValue[key];
} else {
return catchValue[key] = mult.apply(this, arguments);
}
}
})()

缓存代理一般用于缓存已经计算过的结果.用内存换取数度.

缓存代理也经常用于缓存请求过的Ajax请求结果.

高阶函数动态创建缓存代理

可以通过高阶函数,写个创建缓存代理工厂,为各种计算模式创建缓存代理.

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
// 创建缓存代理 工厂
function createProxyFactory (fn) {
var catchValue: {[key: string]: any};
return function () {
var key = Array.propotype.join.call(arguments, ',');
if (catchValue[key]) {
return catchValue[key];
} else {
return catchValue[key] = fn.apply(this, arguments);
}
}
}

// 乘法计算
function mult () {
var a = 1;
for(let i = 0, l = arguments.length; i < l; i++) {
a =a * arguments[i];
};
return a;
}
// 加法计算
function plus () {
var a = 1;
for(let i = 0, l = arguments.length; i < l; i++) {
a =a + arguments[i];
};
return a;
}
var proxyMult = createProxyFactory(mult);
var proxyPlus = createProxyFactory(plus);