前言
今天我们来看一下代理模式,代理模式其实在前端中的使用频率是非常高的。只是可能大部分的开发者并没有感知到。我们很多时候会为了减少直接对dom的操作次数,会先用一个对象实例来反映我们的操作,最后再修改dom。其实这里就可以认为对象实例就是dom实例的代理了。
说明
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
设计思路
代理模式核心解决的应该是让对象功能更单一。举个例子,现在公司的老板有个接受信息的接口,那么假如我们需要给老板发送消息,操作应该如下:
const boss = {
getMsg(msg){
// 处理消息
}
};
boss.getMsg({
// 消息内容
});
但事实上我们发送给老板的信息,可能会非常复杂甚至出现虚假无用信息,老板需要花很多时间来处理阅读。众所周知老板的时间是非常宝贵的,因此一般他会请一个秘书来帮忙收集信息,让后由秘书来整理汇报。由此,我们来修改一下现有的代码。
const boss = {
getMsg(msg){
// 处理消息
}
};
const secretary = {
getMsg(msg){
// 处理消息
const newMsg = handle(msg);
boos.getMsg(newMsg);
}
};
secretary.getMsg({
// 消息内容
});
现在上方修改后的代码,就是代理模式的结构了。大家可以发现,我们从直接给老板发信息,变成了先给秘书发信息,秘书处理过后,再由秘书给老板发送信息。
这样的变化可以带来以下的好处:
- 老板的getMsg功能可以变得更加单一,不需要加太多的对信息的处理。
- 由秘书代理老板之后,秘书可以对信息作更多细节处理。
代理模式的种类
代理模式可以根据代理所实现的功能分成多个种类。
保护代理
保护代理主要是指,代理实例尽可能地保证目标实例的功能正常。因此通常代理会做一些像数据筛选,格式整理等功能。
const secretary = {
getMsg(msg){
// ...只把紧急认为给老板
if(msg.priority !== 'hight' ){
boos.getMsg(msg);
}
}
};
虚拟代理
虚拟代理一般是指,把某些大开销的操作放在合适的时候执行。
const secretary = {
getMsg(msg){
boss.listenMood(function(){
// 假如这里是一个大开销的操作
const task = new Task();
boos.getMsg(task);
})
}
};
缓存代理
缓存代理就很好理解了,就是在代理中加一层缓存。这里假设每次给老板发了信息之后,都会有回复。秘书就可以把老板的回复缓存起来,下次如果有客户问到同样的问题,秘书就可以直接把上次老板的回复给他。
const secretary = {
answers:{},
getMsg(msg){
if(this.answers[mgs]){
return this.answers[mgs];
}else{
const answer = boss.getMsg(msg);
this.answers[mgs] = answer;
}
}
};
更多
代理模式可以实现的功能当然不仅仅只有这3种,还要其他像,防火墙代理,远程代理,智能引用代理等。有兴趣的朋友可以自行查阅。
总结
相信大部分的开发者看到这里都能发现,其实自己过去写的代码里或多或少都用到了代理模式的思想。因为代理模式本身就是一种非常通用的结构。希望大家在阅读完这篇文章之后,可以回顾一下自己写过的相似代码。思想一下有没有进一步优化的空间。
参考
《JavaScript设计模式与开发实践》—— 曾探