定义
代理模式(Proxy Pattern)属于结构型设计模式。让真实的对象有个“替身”,当客户端访问系统时,其实是在访问这个“替身”,这个“替身”用来缓解真实对象的压力,解耦的同时也对性能有所提升。
当外界不满足访问对象的要求时,需要代理模式对访问进行控制,提升系统的安全级别。所以代理对象可以帮真实对象进行过滤和筛选,当访问请求是符合条件的就放行,不符合条件的就过滤掉。
举例说明
某知名艺人淡出大众视野好多年,最近王者复出疯狂接活儿,甚至可以在一个工作中找到下一份工作。这名艺人自身实力过硬,深得广大甲方的喜爱,事业蒸蒸日上。那么试想,如果所有的商单都找到这名艺人,这名艺人的日常会苦不堪言,在保持业务水准的同时还要时刻操心各种商务价值。
这些商单可能只有极少部分是符合艺人团队的利益,那么艺人如果对所有大大小小的商单都要一一查看比对,那其实绝大多数是在浪费时间。所以,经纪人的角色就自然而然,就像是这名艺人的“代理”,帮助艺人过滤一些没有价值的商单,做出最符合团队利益的选项。这就是代理模式!
与适配器模式的异同
相同点
- 都使用了“中介”的角色,用来解耦客户端和系统内部的逻辑。
- 都属于结构型设计模式,提高了代码的可维护性。
不同点
主要是使用场景上的差异,适配器模式更适用于多种外界信息标准的统一处理,而代理模式更多是对客户端访问系统内部的取舍。
一句话的例子,秦统一六国“车同轨、书同文”属于适配器模式,秦始皇吃饭前有太监试吃属于代理模式。
代码实现
根据代理模式的定义和思想,我们需要定义一个接口IService,让“代理”和“本体”都需要基于这个接口的规范和约束。艺人Allen类,实现IService接口,经纪人Dragon类也实现IService接口,内部处理客户端访问的逻辑。
客户端new一个艺人的实例对象,再new一个经纪人的实例对象,将艺人的实例对象传入,用来保证当访问通过时与艺人实例进行通信。然后调用让经纪人类去谈商单,当经纪人对象中的operation方法判断通过后,使用刚传入艺人的实例对象调用operation方法,从而交给艺人去处理商单。
// 代理服务接口 interface IService{ operation(): void; // 服务对象的操作 } // 真实的服务对象 艺人(Allen苏) class Allen implements IService{ operation(): void { console.log('Allen找到了新的工作'); } } // 代理对象 经纪人(龙哥) 1、要实现与真实服务相同的接口 2、需要对访问进行过滤,筛选出符合要求的请求 3、对符合要求的访问进行转发 class Dragon implements IService { private rService: Allen; constructor(r: Allen) { this.rService = r; } operation() :void { // 对外界访问过滤 if (this.checkAccess()) { // 通过访问控制后 转发给真实服务对象 this.rService.operation(); } } // 过滤访问 checkAccess(): boolean { console.log('龙哥同意了这笔商单'); return true; } } // 客户端 const allen = new Allen(); const proxy = new Dragon(allen); // 与代理类经纪人龙哥打交道 谈商单 proxy.operation();
输出结果如下,在访问代理时,核心是checkAccess方法,用来接受或过滤访问,当访问通过时,再交给系统内部去处理。
前端中的代理模式
比如在性能优化中tree-shaking,去拿掉那些未使用的代码,从而减少打包体积;比如权限控制,当接口status返回“无权限”时,跳到登陆页,正常返回则正常处理。再比如ES6中的proxy构造方法,通过代理拦截,加入一些自定义代码。
总结
代理模式算是一个很常见的设计思想,日常工作中也是如此,我们也在时刻扮演“代理者”,领导给我们指派了一些任务,我们去处理一些自己能够解决的问题,如果需要资源再找领导协商,也像是在帮领导“把关”。前端必须掌握的设计模式系列持续更新,如果对您有帮助希望多多点赞哦!