9

本回内容介绍

上一回,聊了代理模式,虚拟代理,图片懒加载,介一回,也比较容易,适配器模式(Adapter),用一个新的接口对现有类的接口进行包装,处理类与API的不匹配。使用这种模式的对象又叫做包装器(wrapper)。先看个简单的例子,先理解再深入,走你:

1.适配器模式

先定义一个接口(接收3个参数),再定义一个对象,如何衔接二者呢,如下:

// 定义一个接口方法,传3个参数
function interfaceMethod(a1,a2,a3){
    // 随便写个弹出框
    alert(a1+a2+a3+'');
}
    
// 定义一个对象
var o = {
    s1:'飞狐就是帅',
    s2:',撸壕,',
    s3:'大卫'
}
    
// 适配器函数,把传递的对象参数转换为interfaceMethod函数需要的形式
function adapter(o){
    interfaceMethod(o.s1,o.s2,o.s3);
}
adapter(o);    //飞狐就是帅,撸壕,大卫

这是模拟JS设计模式书上例子,适配器的作用主要是对现有的接口进行包装,从而实现现有的接口和不兼容的类进行匹配。
这里很多盆友会疑惑适配器模式与门面模式的区别:
1,门面模式是为了简化一个接口,并不提供额外的选择;
2,适配器则要把一个接口转换为另一个接口,并不会滤除某些能力,也不会简化接口;
网上最多的一个例子,就是适配不同的库,如下:

2. 适配不同库

Prototype库的$函数到YUI的get方法的转换,网上最多的一个适配器模式的讲解,看例子:

<div id="fox1">飞狐</div><br/>
<div id="fox2">帅狐</div><br/>    
<div id="fox3">主要看气质</div>
// 模拟Prototype,根据id获取DOM元素,不需要传递任何的形参,一个id写一个参数,多个id多个参数
function $(){
    // 定义一个结果数组
    var elements = [];
    // 遍历传入参数
    for(var i=0;i<arguments.length;i++){
        var element = arguments[i];
        // 判断是否为字符串
        if(typeof element =='string'){
            element = document.getElementById(element);
        }
        // 判断长度,如果是一个,则返回一个
        if(arguments.length==1) return element;
        // 否则加入数组
        elements.push(element);
    }
    // 返回数组
    return elements;
}

// 模拟雅虎
var YAHOO = {};
// YUI中get只接受一个参数,字符串或数组
YAHOO.get = function(el){
    // 判断是否为字符串
    if(typeof el == 'string'){
        return document.getElementById(el);
    };
    // 判断是否为数组
    if(el instanceof Array){
        var elements = [] ;
        for(var i=0;i<el.length;i++){
            elements[elements.length] = YAHOO.get(el[i]);
        }
        return elements;
    }
    // 如果都不是,直接返回
    if(el){
        return el;
    }
    // 否则返回null
    return null;
}
    
// YUI适配器
YAHOO.get = YUIToPrototypeAdapter;
// 适配器函数
function YUIToPrototypeAdapter(){
    // 对于YUI开发人员来说 永远传递一个参数
    if(arguments.length == 1){
        var el = arguments[0];
        // 这里判断是否为数组,如果是直接返回,否则包装成数组返回,如:"a",包装后["a"]
        return $.apply(window,el instanceof Array?el:[el]);
     } else {
         // 如果是多个参数的情况,这里只能用apply,不能用call
         return $.apply(window,arguments);
     }
}

// 测试数组的情况
var arr = YAHOO.get(['fox1','fox2','fox3']);
alert(arr);
// 测试多个参数的情况
var arr = YAHOO.get('fox1','fox2','fox3');
alert(arr);

这个例子在网上太多了,随便找了一个来改,目的在于模拟不同库直接的匹配,灵活的转换,解决与现有API提供的接口不兼容的冲突。

装逼图
装逼时刻了,老片新看,推荐《重庆森林》,文艺范儿的调调~~

这一回聊适配器模式,就俩例子,内容不多,主要是理解。
下面的内容来一个图片预加载,跟上一回的懒加载凑一对兄弟篇。

JS图片预加载

图片预加载是web开发中一种应用相当广泛的技术,比如图片翻转显示等特效的时候,为了让图片在转换的时候不出现等待,先让图片下载到本地,再继续执行后续的操作:

//要加载的图片地址,这里可以随便在网上搜点儿图片测试
var imgs=[
    "xxx.jpg",
    "yyy.jpg",
    "zzz.jpg"
    ];
    
var preload=function(imgs,callback){
    // 判断传入的imgs是否为数组(typeof操作符检测数组的时候也是object),若不是数组则用[imgs]转为数组
    var imgs=(typeof imgs!="object")? [imgs] : imgs;
    // 定义一个图片数组
    var img = [];
    for(var i=0,len=imgs.length;i<len;i++){
        // 为每一个图片对象赋值图片地址
        img[i] = new Image();
        img[i].src = imgs[i];
    }
    
    // 三目运算没什么好说的,len-1表示最后一个图片对象,加载完成执行回调函数,apply还记得吧,使作用域指向img
    img[len-1].onload = callback?callback.apply(img):null;
}
    
// 测试
window.onload=function(){
    preload(imgs,function(){
        var _self = this;
        _self.forEach(function(item){
            alert(item.src);
        })
    });
}

这里只是简单的模拟,代码量少,应该可以很容易看懂,预加载减去了等待时间提高用户体验,很多web应用中广泛运用。

这一回,主要聊了适配器模式,图片预加载,主要还是理解~~
下一回,聊一聊桥接模式,顺便做一做计算题。

客观看完点个赞,推荐推荐呗,嘿嘿~~


注:此系飞狐原创,转载请注明出处


飞狐
2.4k 声望1.4k 粉丝

专注AI量化,技术界最懂金融的CFA金融分析师