代理模式
场景:小明送花记
小明喜欢一群漂亮的女神MM*,所以开始了疯狂的送花行为,开始他自己去送花,发现被别人发现了会影响后面的追求其他女神,所以小明踏上了找代理送花的这条不归路
初识代理
- 小明追MM送花,直接送
- 小明选择MM的好朋友(小明同桌)送花
let Flower = function(flowerName) {
this.flowerName = flowerName
}
let XiaoMing = {
sendFlower : function (target){
let flower = new Flower("牡丹");
target.receiveFlower(flower);
}
}
const MM = {
receiveFlower : function (flower){
console.log("MM收到一束花: " + flower.flowerName)
}
}
const Frient = {
receiveFlower : function(flower){
MM.receiveFlower(flower);
}
}
XiaoMing.sendFlower(MM)
XiaoMing.sendFlower(Frient)
你会发现结果是一样的,所以这个代理有什么用呢???效果都一样嘛!!!会要转手,多麻烦!!!
别着急,继续看下去就知道了
初见代理作用
- 小明上次失败了,他觉得是可能是MM心情不好,所以拒绝了他
- 吸取上次的教训,这次花了多一点钱,找了一个靠谱的代理,朋友2,希望她能在MM2心情好的时候送出花花
let MM2 = {
receiveFlower : function(flower){
console.log("MM2收到一束:" + flower.flowerName)
},
listenGood: function(fn){
// 假设1秒后心情变得特别好
setTimeout(() => {
fn();
}, 1000);
}
}
let Frient2 = {
receiveFlower:function(flower){
MM2.listenGood(() => {
MM2.receiveFlower(flower);
});
}
}
XiaoMing.sendFlower(Frient2)
这里可以看出,代理的作用还是很大的,能决定事件触发执行时间(这里更好的是时机)
代理 - 保护模式
- 小明表白失败了,他觉得是自己买错花了,表白怎么能用牡丹呢?于是买了一束玫瑰准备继续表白
- 找到了第三个MM3,但是这个MM3的朋友知道小明前面的事迹
- MM3的朋友觉得小明太渣了,直接拒绝了帮忙送花的事
XiaoMing = {
sendFlower : function (target){
let flower = new Flower("玫瑰");
target.receiveFlower("小明", flower);
}
}
let MM3 = {
receiveFlower : function(flower){
console.log("MM3收到一束:" + flower.flowerName)
}
}
let Friend3 = {
receiveFlower: function(name , flower){
if(name === "小明"){
console.log(name + ",你不配给我替你送花")
return;
}
MM3.receiveFlower(flower);
}
}
XiaoMing.sendFlower(Friend3);
这里可以看到我们可以在外设置关卡,如果说是渣渣,我们不让进入后面部分,这样可以很好的保护内部
- 小明受不了,“你不帮忙送,怎么不早说”,这接连的失败,然后就委屈巴巴的哭了,嘴里还念叨着:“这是我一个星期的生活费呀!!!”
- 朋友3:“你以前都没有问我呀,我咋知道呢!!!”
- 小明:“哦,原来还是我的错!!!”
- 朋友3看着小明的样子:“看你这样子,只要你耐心改过,不这么花心,我可以考虑帮你一回”
- 小明答应了,于是又改变了,小明会提前问朋友3是否愿意送花,在决定买花
XiaoMing = {
sendFlower : function (target){
target.receiveFlower("小明", function(){
return new Flower("玫瑰");
});
}
}
MM3 = {
receiveFlower : function(flower){
console.log("MM3收到一束:" + flower.flowerName)
}
}
Friend3 = {
receiveFlower: function(name , fn){
if(name === "小明"){
console.log(name + ",你还不配给我替你送花")
return;
}
// 有送花的资格了
let flower = fn();
MM3.receiveFlower(flower);
}
}
XiaoMing.sendFlower(Friend3);
上面不难看出,其实我们可以把一些很消耗资源的事情放在我们通过代理后再做,这样就节省了很多不必要的消耗
代理模式 - 虚拟代理
不使用代理的图片预加载
var myImageNoProxy = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
var img = new Image;
img.onload = function(){
// 模拟加载过程
setTimeout(() => {
imgNode.src = img.src;
}, 1000);
}
return {
setSrc: function(src){
imgNode.src = "../../work/图片/loadding.jpg";
img.src = src;
}
}
}())
myImageNoProxy.setSrc("../../work/图片/test.png")
使用代理的图片预加载
let myImage = (function(){
let imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc:function(src) {
imgNode.src = src;
}
}
}())
myImage.setSrc("../../work/图片/test.png")
let proxyMyImage = (function(){
let img = new Image();
img.onload = function(){
// 模拟加载过程
setTimeout(() => {
myImage.setSrc(img.src)
}, 1000);
}
return {
setSrc:function(src){
myImage.setSrc("../../work/图片/loadding.jpg")
img.src = src;
}
}
}())
proxyMyImage.setSrc("../../work/图片/test.png")
整体来看,其实两个图片的预加载都差不多,但是代理模式相对会好一点,每个方法都有自己的作用,后面有部分图片不需要预加载的时候只需要更换方法,而无需改变方法内部代码
请求统一上传
场景
点击一下复选框就会上传服务器,但是这样比较消耗性能,所以更改为点击的时候先保存在本地,等到不再操作的时候就一起上传上去
let sendToServer = function(id){
console.log("开始上传到服务器... id :" + id);
}
var proxySendToServer = (function(){
var cache = [], // 缓存一段时间内的id列表
timer = null; // 定时器
return function(id){
// 缓存id
cache.push(id);
// 如果上一个timer还在,那么就结束
if(timer){
return;
}
// 否则设置定时器
timer = setTimeout(() => {
// 真正的上传到服务器
sendToServer(cache.join(","));
clearTimeout(timer)
timer = null;
cache = [];
}, 2000);
}
}())
let checkBoxs = document.getElementsByTagName("input");
for (let index = 0; index < checkBoxs.length; index++) {
const element = checkBoxs[index];
element.onclick = function(){
// 使用代理上传到服务器
if(this.checked === true){
proxySendToServer(this.id);
}
}
}
代理总结
代理和本体接口的一致性:通过上面的代码可以看到,我们代理和本体都是暴露了相同的接口,代理接手请求的过程对于用户来说是透明的,用户并不清楚代理和本体的区别
-
用户可以放心请求代理,他只关心是否得到自己想要的结果
-
在任何使用本体的地方都可以直接使用代理替代,反之亦然
代理意义:面向对象中有一个设计原则 ----> 单一职责原则【就是一个类(通常也包括一个对象和函数等)而言,应该仅有一个引起它变化的原因,如果一个对象承担了多项职责,就意味着这个对象将变得巨大,引起它变化的原因可能有很多个。面向对象设计鼓励将行为分布到细粒度的对象中,如果一个对象承担太多职责,等于把这些职责耦合到一起,这种耦合会导致脆弱和低内聚的设计】