代理模式

要解决的问题

代理模式主要解决的问题是将复杂的操作逻辑隐藏起来,让方法的使用者只使用几个固定的setget类方法就可以简单的实现一些功能。而且代码还不失扩展性和维护性。

能解决的常见问题

  • 图片预加载

一般网页上显示图片如果直接img标签中写上src,在用户访问网页时可能因为网速的原因,会显示一大片空白的区域,这样容易引起不明真相的用户的困惑。所以目前一般的网站都会有图片预加载机制,也就是在真正的图片在被加载完成之前用一张菊花图(转圈的gif图片)表示正在加载图片。

<div>
    <h3>这是一张图片标题</h3>
</div>

TS代码

/* 生成一张图片 */
class myImg{
    imgNode = document.createElement("img");
    constructor(where:HTMLElement){
        this.appendTo(where);
    };
    private appendTo(where:any){
        where.appendChild(this.imgNode);
    }
    setSrc( src:string ){
        this.imgNode.src = src;
    }
}
/* 封装一个类嗲用前一个类,等待网络图片加载完成之前先设置一张loading菊花图,加载完成后将图片换成该显示的图片 */
class PreloadImg extends myImg{
    img = new Image;
    constructor( where: HTMLElement){
        super(where);
    }
    setSrc(src:string){
        super.setSrc('loading.gif')
        this.img.src = src;
        this.img.onload = ()=>{
            super.setSrc(src);
        }
    }
}

/*循环调用前一个类,插入图片的显示列表*/
class LoadImgList extends PreloadImg{
    constructor(list:string[],place:HTMLElement){
        super(place);
        list.map((item)=>{
            super.setSrc(item);            
        })
    }
}

/*  Test  */
let place = document.getElementsByTagName('div')[0];
let list = [
    "图片链接1",
    "图片链接2",
    "图片链接3",
];
new LoadImgList(list,place); //插入显示图片列表

可以看出上面的代码实现的两层的代理,符合单一职责的原则
1.myImg类的作用是在指定的位置插入一张图片,并有setSrc的方法用来为图片设置路径。
2.PreloadImg类继承了myImg,作用是用来在加载图片的过程中先显示一张占位的loading菊花图,而在图片加载完毕后将占位菊花图换成加载下来的图片。
3.LoadImgList类继承了PreloadImg类,作用是用来将图片队数组中的图片链接自动的加载到图片要插入的地方。
4.可以看出代理模式是将复杂的逻辑一步一步的封装到每个类中,而且每个类都有自己唯一的职责。而用户只要使用最后的LoadImgList类不用理会背后的逻辑就可以使用图片预加载功能。同时代码也具有可扩展性和相对好的可维护性。

  • 缓存计算结果
/* 用到了 单例模式 和 代理模式:用代理模式实现单例模式实现计算的缓存*/

/*负责计算相乘的结果*/
class Mult{
    protected getResult(...args){
        console.log('开始计算');
        return args.reduce((x,y)=>{
            return x*y;
        });
    }
}

/*代理Mult类,缓存计算的内容*/
class CacheMult extends Mult{
    cache:object = {};
    constructor(){
        super();
    }
    getResult(...args){
        let sorted_args = args.sort((n1,n2)=>n1-n2);
        let key = sorted_args.join(",")
        if ( key in this.cache ){  //如果结果已经计算过了,就返回缓存过的结果
            return this.cache[key];
        }else{
            let result = super.getResult(...args);  //调用父类得到计算结果
            this.cache[ key ] = result; //缓存结果到缓存中
            return result;
        }
    }
}

let mult = new CacheMult();
let r1 = mult.getResult(1,2,3,4);
let r2 = mult.getResult(1,2,3,4);
let r3 = mult.getResult(1,2,3);
console.log(r1);
console.log(r2);
console.log(r3);
/* 运行结果 */
// 开始计算
// 开始计算
// 24
// 24
// 6

从上面的代码中可以看出,CacheMult类代理了Mult类来事项缓存计算结果的功能,防止出现重复计算,这样可以再某一些计算密集型的场景下有效的节省计算资源,提高代码的性能。


沐风
162 声望9 粉丝