设计模式之代理模式
1. 定义
为其他对象提供一种代理用以控制对这个对象的访问
2. 口语化表述
代理,在日常生活中很常见
比如找朋友替你拿个快递,此时的这个朋友就是代理者,并且按规范而言,他拿快递时,需要在快递单上的“代理签收”栏签上他的名字
此时的代理,就是替你签收快递的这个朋友,他能做一些需要你做的事(如,签收快递),也能对你的快递包裹做一些事情(如,他可以帮你拆包)
能代替你做一些事情,也能对这些事情做一些他的行为,这就是代理模式
(下面的描述会沿用这个上述这个场景)
3. 源码示例
代理在前端可太常见了,ES 6 中就有Proxy对象
ES 6 的Proxy对象,就是将需要代理的对象进行拦截,从而可以实现一些额外的操作
比如下面的示例:
const obj = {
count: 0
}
// 对obj进行代理
const proxy = new Proxy(obj, {
get(target, key) {
// 拦截get方法并加入自定义的方法,这里是输出一句 "count: 0"
return console.log("count:", target.count)
}
})
obj.count // 0
proxy.count // "count: 0"
从代码可以看出,通过代理,可以实现拦截注入
代理是Vue实现响应式的核心原理,Vue3使用Proxy实现响应式数据对象
下面是Vue3的Reactive
对象的创建函数:
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// ...
// target already has corresponding Proxy
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// only specific value types can be observed.
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
可以看到,Vue3中使用代理实现响应式对象,从而实现数据的实时渲染
4. 总结
4.1 设计优点
-
在客户端毫无察觉的情况下控制服务对象
-
客户端对服务对象的生命周期进行管理
-
开闭原则
可以在不对原始对象做出修改的情况下创建新代理
4.2 适用场景
-
访问控制(保护代理)
-
缓存请求结果(缓存代理)
-
延迟初始化(虚拟代理)
5. 参考资料
[1] 代理设计模式 (refactoringguru.cn)
[2] core/packages/reactivity/src/reactive.ts at main · vuejs/core (github.com)