代理模式,简单的理解就是有一个代理人的角色,会去帮你谈事情。相当于明星身边的经纪人所做的事情一样。
举个例子,js中的事件委托机制想必大家都不陌生。没错,事件委托机制也是一个代理模式。
<ul id="ul">
<li>来了老妹</li>
<li class='li'>来了老弟</li>
<li>来了媳妇</li>
<li>来了老公</li>
</ul>
//js
var li = document.getElementsByTagName("li")
console.log(li);
for(let i=0;i<li.length;i++){
li[i].onclick = function(){
this.style.background = "skyblue"
}
}
没用事件委托之前都是给每个li标签添加点击事件,但是这样会增加内存损耗
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
//多种写法,看自己适合哪种用哪种
//if (e.target.className=="li") {
//if (e.target.matches("ul>li")) {
if (target.nodeName.toLocaleLowerCase() === 'li') {
console.log('li: ', target.innerHTML);
}
});
这里li需要做的事情,让ul代理去做了,实现了代理机制,减少了内存消耗。
vue3的proxy想必大家也是熟悉的,这也是一个代理模式
//用法
const p = new Proxy(target, handler)
target :要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler :一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时,代理 p 的行为。
对于社交软件大家应该都是挺熟悉的
首先,自己会去填个人信息,然后就可以去软件中的广场找帅哥靓女聊天了。
// 靓妹
const girl = {
// 姓名
name: '小美',
// 自我介绍
instruction: 'xxx'
// 年龄
age: 24,
// 职业
career: 'teacher',
// 手机号
phone: 123456,
//照片
photo:'xxx'
}
但是点击他们的信息就会发现,很多资料是看不到的。为什么呢?大家资料必填项都填了吧。主要是因为做了限制需要去开通vip和实名认证
// 普通私密信息
const baseInfo = ['age', 'career']
// 最私密信息
const privateInfo = ['photo', 'phone']
// 用户(自己)对象实例
const user = {
...(必填项的个人信息)
isValidated: true, //实名认证
isVIP: false,//vip
}
// 社交软件tantan登场了
const tantan= new Proxy(girl, {
get: function(girl, key) {
if(baseInfo.indexOf(key)!==-1 && !user.isValidated) {
alert('您还没有完成验证哦')
return
}
//...(此处省略其它有的没的各种校验逻辑)
// 此处我们认为只有验证过的用户才可以购买VIP
if(user.isValidated && privateInfo.indexOf(key) && !user.isVIP) {
alert('只有VIP才可以查看该信息哦')
return
}
}
})
以上主要是 getter 层面的拦截。假设我们还允许会员间互送礼物,每个会员可以告知软件自己愿意接受的礼物的价格下限,我们还可以作 setter 层面的拦截。:
// 规定礼物的数据结构由type和value组成
const present = {
type: '荧光棒',
value: 1,
}
// 为用户增开presents字段存储礼物
const girl = {
// 姓名
name: '小美',
// 自我介绍
instruction: 'xxx'
// 年龄
age: 24,
// 职业
career: 'teacher',
// 手机号
phone: 123456,
//照片
photo:'xxx',
// 礼物数组
presents: [],
// 拒收50块以下的礼物
bottomValue: 50,
// 记录最近一次收到的礼物
lastPresent: present,
}
// tantan推出了小礼物功能
const tantan= new Proxy(girl, {
get: function(girl, key) {
if(baseInfo.indexOf(key)!==-1 && !user.isValidated) {
alert('您还没有完成验证哦')
return
}
//...(此处省略其它有的没的各种校验逻辑)
// 此处我们认为只有验证过的用户才可以购买VIP
if(user.isValidated && privateInfo.indexOf(key)!==-1 && !user.isVIP) {
alert('只有VIP才可以查看该信息哦')
return
}
}
set: function(girl, key, val) {
// 最近一次送来的礼物会尝试赋值给lastPresent字段
if(key === 'lastPresent') {
if(val.value < girl.bottomValue) {
alert('sorry,您的礼物被拒收了')
return
}
// 如果没有拒收,则赋值成功,同时并入presents数组
girl.lastPresent = val
girl.presents = [...girl.presents, val]
}
}
})
代理模式的用处:我们遵循面向对象设计原则的单一职责原则:一个对象应该尽可能少的承担职责,最好是一个,如果承担职责过多,会提高代码的耦合度,从而导致脆弱和低内聚的设计。当变化发生,设计可能遭到意外破坏,即使实现同样需求可以将代码封装到一个函数中,但是最好的处理措施是引入代理模式