代理模式
# 代理模式
# 概述
代理模式属于设计模式中结构型的设计模式;
# 定义:
顾名思义就是为一个对象提供一个代用品或占位符,以便控制对它的访问!
# 白话解释:
1.很多老板都有秘书,如果需要给老板写建议信,需要秘书现看一遍,秘书会把这些信件过滤一遍,然后在把有价值的信件给老板看;
2.我们找房子的时候很难去找到房东,房东发布租房信息也比较麻烦,这时候我们就会想到中介,中介其实也是一种代理模式,房东只需要给中介说我要出租房子,我们想要租房住的时候只需要找到中介即可。
# 实现方法
# 例子说明一:
小明遇见了他的百分百女孩,我们暂且称呼小明的女神为A。两天之后,小明决定给A送一東花来表白。刚好小明打听到A和他有一个共同的朋友B,于是内向的小明决定让B来代替自己完成送花这件事情
先看看不用代理方法
const Flower = function (){};
const xiaoming = {
sendFlower: function(target) {
const flower = new Flower();
target.receiveFlower(flower);
}
}
const A = {
receiveFlower: function(flower) {
console.log(`收到花${flower}`)
}
};
xiaoming.sendFlower(A);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
接下来我们引用代理B,即小明通过B来给A送花
const Flower = function (){};
const xiaoming = {
sendFlower: function(target) {
const flower = new Flower();
target.receiveFlower(flower);
}
}
const B = {
receiveFlower: function(flower) {
A.receiveFlower(flower);
}
}
const A = {
receiveFlower: function(flower) {
console.log(`收到花${flower}`)
}
};
xiaoming.sendFlower(B);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
很显然,执行结果跟第一段代码一致,至此我们就完成了个最简单的代理模式的编写。也许读者会疑惑,小明自己去送花和代理B帮小明送花,者看起来并没有本质的区别,引入一个代理对象看起来只是把事情搞复杂了而已。
的确,此处的代理模式毫无用处,它所做的只是把请求简单地转交给本体。但不管怎样,我们开始引入了代理,这是一不错的起点。现在我们改变故事的背景设定,假设当A在心情好的时候收到花,小明表白成功的几率有60%,而当A在心情差的时候收到花,小明表白的成功率无限趋近于0。小明跟A刚刚认识两天,还无法辨别A什么时候心情好。如果不合时宜地把花送给A,花被直接扔掉的可能性很大,这束花可是小明吃了7天泡面换来的。但是A的朋友B却很了解A,所以小明只管把花交给B,B会监听A的心情变化,然后选择A心情好的时候把花转交给A,代码如下
const Flower = function (){};
const xiaoming = {
sendFlower: function(target) {
const flower = new Flower();
target.receiveFlower(flower);
}
}
const B = {
receiveFlower: function(flower) {
A.listenGoodMood(function() {
// 监听A的好心情
A.receiveFlower(flower);
});
}
}
const A = {
receiveFlower: function(flower) {
console.log(`收到花${flower}`);
},
listenGoodMood: function(fn) {
setTimeout(function() { // 假设10秒后A的心情变好
fn();
}, 1000 * 5);
}
};
xiaoming.sendFlower(B);
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
保护代理和虚拟代理
虽然这只是个虚拟的例子,但我们可以从中找到两种代理模式的身影。代理B可以帮助A过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理B处被拒绝掉。这种代理叫作保护代理。A和B一个充当白脸,一个充当黑脸。白脸A继续保持良好的女神形象,不希望直接拒绝任何人,于是找了黑脸B来控制对A的访问。另外,假设现实中的花价格不菲,导致在程序世界里,neWFlower也是一个代价昂贵的操作,那么我们可以把new Flower的操作交给代理B去执行,代理B会选择在A心情好时再执行new Flower,这是代理模式的另一种形式,叫作虚拟代理。虛拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。代码如下
const B = {
receiveFlower: function(flower) {
A.listenGoodMood(function() {
// 监听A的好心情
var flower = new Flower(); // 延迟创建对象
A.receiveFlower(flower);
});
}
};
2
3
4
5
6
7
8
9
保护代理用于控制不同权限的对象对目标对象的访问,但在Javascript并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,本章主要讨论的也是虚拟代理。当然上面只是一个虚拟的例子,我们无需在此投入过多近精力,接下来我们看另外一个真实的示例
# 例子说明二:虚拟代理实现图片懒加载
没用代理的时候我们的代码是这样的:
// 创建一个本体对象
var myImage = (function(){
// 创建标签
var imgNode = document.createElement( 'img' );
// 添加到页面
document.body.appendChild( imgNode );
return {
// 设置图片的src
setSrc: function( src ){
// 更改src
imgNode.src = src;
}
}
})();
myImage.setSrc( 'https://www.maoyali.cn/img/ui.png' );
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们把网速调至5KB/s,然后通过 Mylmage.setSrc给该img节点设置src,可以看到,在图片被加载好之前,页面中有一段长长的空白时间。现在开始引入代理对象 proxylmage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的菊花图loading gif,来提示用户图片正在加载。代码如下
// 创建一个本体对象
var myImage = (function(){
// 创建标签
var imgNode = document.createElement( 'img' );
// 添加到页面
document.body.appendChild( imgNode );
return {
// 设置图片的src
setSrc: function( src ){
// 更改src
imgNode.src = src;
}
}
})();
// 创建代理对象
var proxyImage = (function(){
// 创建一个新的img标签
var img = new Image;
// img 加载完成事件
img.onload = function(){
// 调用 myImage 替换src方法
myImage.setSrc( this.src );
}
return {
// 代理设置地址
setSrc: function( src ){
// 预加载 loading
myImage.setSrc( './loading.gif' );
// 赋值正常图片地址
img.src = src;
}
}
})();
proxyImage.setSrc( 'https://www.maoyali.cn/img/ui.png' );
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
上面这段代码运用代理模式来实现图片预加载,可以看到通过代理模式巧妙地将创建图片与预加载逻辑分离,并且在未来如果不需要预加载,只要改成请求本体代替请求代理对象就行。
以上就是JavaScript设计模式学习之代理模式的详细内容。