当前位置: 首页 > Web前端 > HTML5

从ES6重新认识JavaScript设计模式(四):AdapterMode

时间:2023-04-05 17:27:15 HTML5

1什么是AdapterMode适配器模式(Adapter):将一个类的接口转换成客户想要的另一个接口,使得它们不能一起使用,因为不兼容的接口那些工作的类可以一起工作。在生活中,我们有很多适配器。比如iPhone7之后的耳机接口,就从原来的3.5mm圆孔接口变成了苹果专属的闪电接口。很多人以前的圆孔耳机需要下面的转接头才能在新买的iPhone上听音乐。在前端开发中,我们可能会遇到这样的场景:当我们试图调用某个模块或对象的接口时,发现这个接口的格式不符合我们的需求。这时候有两种解决方案:第一种是修改原来的接口实现,但是如果原来的代码很复杂,比如库或者框架,那么改变原来的代码是不现实的。那么这个时候,就需要用到今天说的第二种方法:创建一个适配器,将原来的接口转换成客户想要的另一个接口,客户只需要使用适配器即可。对于只接触过JavaScript语言的前端开发者来说,接口这个概念可能比较陌生。建议参考TypeScript接口文档以更好地理解接口。2ES6中的适配器模式在前端项目中,适配器模式的使用场景一般有以下三种情况:库适配、参数适配和数据适配。下面我将以我在项目中的实际例子来说明。2.1库适配项目上线前,通常需要前端开发者在页面中接入SDK统计网页数据。这些SDK可以收集用户信息和网页行,生成可视化的图表和表格,帮助网站运营商和产品经理更好地根据用户行为提高网页质量。我们来看看适配器在连接数据采集库时的使用场景:目前国内做的比较好的数据分析网站有百度统计、神策数据、友盟等,之前有一个电商网站你做的项目上线,你的产品经理让你接入百度的代码进行数据采集,在涉及用户运营的几十个地方埋点。百度统计提供的埋点接口格式如下:_hmt.push(['_trackEvent',category,action,opt_label,opt_value]);根据产品经理的要求,你把埋点代码按照上面的格式写到页面的多个部分place://index.html_hmt.push(['_trackEvent','web','page_enter','位置','index.html']);//product-detail.html_hmt.push(['_trackEvent','web','page_enter','position','product-detail.html']);_hmt.push(['_trackEvent','web','product_detail_view','product_id',productId]);_hmt.push(['_trackEvent','web','add-product-chart','product_id',productId]);//...还有几十个页数。几个月后,电商网站的发展速度很快,运营商们觉得百度统计提供的采集数据已经不能满足现在网站的规模了。与运营商和产品经理商量后,决定数据采集平台需要从百度统计切换到神策数据。神策数据提供的埋点接口格式如下:sa.??track(eventName,{attrName:value})接口的规则不同。也就是说,你需要把百度统计的几十个_htm.push接口改成神策提供的sa.track接口。其实不用那么麻烦,可以自己写一个adapter来完成所有内嵌事件的迁移://app.jslet_hmt={push:(arr){const[eventName,attrName,value]=[...arr.splice(2)];让attrObj={[attrName]:值};sa.track(eventName,attrObj);}}通过百度统计的接口和Sensors的接口分析对比,我们可以知道,Sensors中只有三个参数,eventName对应百度统计接口中的action,attrName对应百度统计接口中的opt_label,以及value对应百度统计接口中的opt_value;删除百度统计SDK后,SDK提供的_htm全局变量不存在了,我们可以使用变量名作为适配器,在push方法中获取sa.track需要的三个参数,调用sa.track。2.2参数适配在某些情况下,一个方法可能需要传入多个参数。比如SDK类中有一个phoneStatus,需要传入五个参数来接收手机的相关信息:....}}通常当传入的参数大于3时,我们可以考虑将参数合并为一个对象,就像我们的$.ajax一样。下面我们可以定义phoneStatus的参数接口如下(String表示参数类型,?:表示可选){brand:Stringos:Stringcarrier:?字符串语言:?串网:?String}可以看出carrier,language,network这三个属性不需要传入,可以在方法内部设置一些默认值。所以这时候我们可以在方法内部使用一个适配器来适配这个参数对象。classSDK{phoneStatus(config){letdefaultConfig={brand:null,//手机品牌os:null,//系统类型:Andoird或iOScarrier:'china-mobile',//operator,defaultChinaMobilelanguage:'zh',//语言类型,默认中文网络:'wifi',//网络类型,默认wifi}//参数适配(letiinconfig){defaultConfig[i]=config[i]||默认配置[i];}//dosomething.....}}2.3数据适配数据适配是前端最常见的场景。这时候适配器就起到了解决前后端数据依赖的重要作用。通常服务端传过来的数据和我们前端需要使用的数据格式是不一致的,尤其是在使用一些UI框架的时候,框架规定的数据是有固定格式的。所以,这时候我们就需要对后端的数据格式进行适配。比如网站上有个每周uv,使用网页中的Echarts折线图。通常,后端返回的数据格式如下:[{"day":"Monday","uv":6300},{"day":"Tuesday","uv":7100},{"day":"Wednesday","uv":4300},{"day":"Thursday","uv":3300},{"day":"WeekFive","uv":8300},{"day":"Saturday","uv":9300},{"day":"Sunday","uv":11300}]但是Echarts需要的x轴数据格式和坐标点数据如下:["Tuesday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]//x轴数据[6300.7100,4300,3300,8300,9300,11300]//坐标点的数据,所以我们可以使用适配器适配后端返回的数据://x轴适配器函数echartXAxisAdapter(res){returnres.map(item=>item.day);}//坐标点适配器函数echartDataAdapter(res){returnres.map(item=>item.uv);}3总结Adapter模式在JS中有很多使用场景。在参数适配方面,很多库和框架都采用了适配器模式;数据适配对于解决前后端数据依赖非常重要。但适配器模式本质上是一种拼凑模式,它解决了现有两种接口不兼容的问题。你不应该在软件开发的初始阶段使用这种模式;如果我们在设计之初就能够协调好规划好的接口的一致性,那么应该尽量少用适配器。参考文献:[1]张荣明JavaScript设计模式[M].人民邮电出版社[2]程杰大话设计模式[M].清华大学出版社[3]曾坦JavaScript设计模式与开发实践[M].r人民邮电出版社