代理模式:通过一个中间对象,控制对真实想要调用对象的访问.
代理模式的用途:
代理将接受的信息 加工处理后传给本体,还可以控制本体接受数据的速率.
代理帮助缓存本体已经处理过的数据.
代理校验是否有权限访问本体.
在前端场景常见的代理模式有:
1. 保护代理: 代理校验访问本体权限,帮本体过滤信息.
2. 虚拟代理: 代理在本体可以接受信息的时候传递信息给它.
3. 缓存代理: 缓存处理过的数据,当再次请求时不需要给本体处理.
保护代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class ProxyDoor { door :{new (): Door}; constructor ( ) { this .door = new Door; } open (pw:string ) { if (this .authenticate(pw)) { return this .door.open(); } else { return {status : false ,msg : '开门密码错误!' } } }; authenticate (pw: string ) { return pw === 'passsord' ; } } class Door { constructor ( ) {} open ( ) { return { status : true , msg : '门🚪已打开!' } } }
虚拟代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class LoadImage { imageNode : HTMLElement; constructor ( ) { this .imageNode = document .createElement('img' ); document .body.appendChil(imageNode); } setSrc (src: string ) { this .imageNode.src = src } } class ProxyLoadImage { img : Image; loadImage: {new (): LoadImage}; constructor ( ) { self = this ; self.img = new Image; self.loadImage = new LoadImage() self.img.onload = function ( ) { self.loadImage.setSrc(this .src) } } setSrc (src: string ) { this .loadImage('./img/xxx.png' ); this .img.src = src; } }
上面👆这段代码,是前端中最常见的图片预加载.当真实图片没加载完成时,在图片位置上先用本地的小图当占位符.
图片预加载不用代理模式也可以很简单的实现,为什么要用代理模式呢.是因为,面向对象设计原则之一是: 单一职责原则.
单一职责原则:一个类(方法,对象),只有一个因素会引起它的变化.
如果一个类(方法,对象)自身有多个因素会导致它变化,说明它承担的职责太多,这些职责耦合在一起.并不利于它的维护和扩展.
上面的代码中,将预加载和展示图片分离开来.代理负责预加载,本体只负责展示图像.这样代码更清晰,灵活.
缓存代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function mult ( ) { var a = 1 ; for (let i = 0 , l = arguments .length; i < l; i++) { a =a * arguments [i]; }; return a; } proxMult = (function ( ) { var catchValue: {[key:string ]: number }= {}; return function ( ) { let key = Array .prototype.join.call(arguments ,',' ); if (key in catchValue) { return catchValue[key]; } else { return catchValue[key] = mult.apply(this , arguments ); } } })()
缓存代理一般用于缓存已经计算过的结果.用内存换取数度.
缓存代理也经常用于缓存请求过的Ajax请求结果.
高阶函数动态创建缓存代理 可以通过高阶函数,写个创建缓存代理工厂,为各种计算模式创建缓存代理.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function createProxyFactory (fn ) { var catchValue: {[key: string ]: any }; return function ( ) { var key = Array .propotype.join.call(arguments , ',' ); if (catchValue[key]) { return catchValue[key]; } else { return catchValue[key] = fn.apply(this , arguments ); } } } function mult ( ) { var a = 1 ; for (let i = 0 , l = arguments .length; i < l; i++) { a =a * arguments [i]; }; return a; } function plus ( ) { var a = 1 ; for (let i = 0 , l = arguments .length; i < l; i++) { a =a + arguments [i]; }; return a; } var proxyMult = createProxyFactory(mult);var proxyPlus = createProxyFactory(plus);