代码写了好几年了,设计模式处于忘我忘我的状态。大多数关于设计模式的文章都使用基于类的静态类型语言,例如Java和C++。作为前端开发人员,js是一门基于原型的动态语言。职能已成为一等公民。模式略有不同,甚至简单得不像使用设计模式,有时会引起一些混淆。下面按照“场景”-“设计模式定义”-“代码实现”-“更多场景”-“通用”的顺序进行总结。如有不妥之处,欢迎交流讨论。场景我们在使用第三方库的时候,经常会遇到当前接口与第三方接口不匹配的情况,比如使用了一个Table组件,这就需要我们返回表格数据,格式如下:{code:0,//业务代码msg:'',//出错时提示data:{total:,//总数量列表:[],//表格列表}};但是后台返回的数据可能是这样的:{code:0,//业务代码message:'',//出错时提示data:{total:,//总数量记录:[],//表列表}};此时可以通过adapter方式进行转换。看一下维基百科给适配器模式的定义:在软件工程中,适配器模式是一种软件设计模式,它允许将现有类的接口用作另一个接口。[1]它通常用于使现有类与其他类一起工作,而无需修改它们的源代码。”通过适配器模式,可以在不改变当前类的情况下,正常使用另一个类。基于类的语言有两种实现方式,一种是通过组合,适配器类包含原始对象的实例。一种是通过类继承,适配器类继承原来的类。可以看看UML类图:image-20220213124112500左边的Adapter里面有一个Adaptee的实例,右边的Adapter类直接继承了Adaptee类。Adapter将Adaptee的具体Operation方法处理并封装成一个操作方法供client使用。看个简单的例子,在现实生活中,iPhone有两个耳机接口,一个是Lightning,一个是传统的3.5mm接口。如果您想将带有闪电插孔的耳机插入带有传统3.5毫米插孔的电脑,您需要一个适配器。classLightning耳机{publicvoidinsertintoLightinginterface(){System.out.println("插入Lightning耳机接口成功");}}classtraditionalearphone{publicvoidinsertintotraditionalearphonejack(){System.out.println("插入传统耳机孔成功");}}classLightning耳机转传统耳机转接器扩展传统耳机{publicLightningearphoneLightningearphone;publicLightning耳机转传统耳机转接头(Lightningearphoneearphone){Lightningearphone=earphone;}publicvoid插入传统耳机接口(){Lightning耳机.插入Lighting接口();}}class电脑传统耳机插孔{public传统耳机earphone;公用电脑传统耳机插孔(traditionalearphone传统耳机){earphone=traditionalearphone;}publicvoidInsertearphones(){earphone.Insertintotraditionalearphonesjack();}}}publicclassMain{publicstaticvoidmain(String[]args){传统耳机traditionalearphone=newtraditionalearphone();电脑传统耳机孔电脑传统耳机孔=新电脑传统耳机孔(传统耳机);电脑传统耳机插孔.insertearphone();//成功插入传统耳机接口Lightning耳机Lightningearphone=newLightningearphone();电脑传统耳机插孔电脑传统耳机插孔2=新电脑传统耳机插孔(新Lightning耳机转传统耳机转接头(Lightning耳机));电脑传统耳机接口2.插入耳机();//插入Lightning耳机接口成功}}通过适配器我们将Lightning耳机成功插入电脑传统的耳机接口,让我们用js重写。constLightning耳机={插入Lightning接口(){console.log("插入Lightning耳机接口成功");}}constTraditionalearphones={插入传统耳机孔(){console.log("插入传统耳机孔成功");}}constcomputerheadphonejack={插入耳机(耳机){headphones.pluggedintolegacyheadphonejack();}}constLightningheadphonestolegacyheadphoneadapter=function(Lightningheadphones){return{插入传统耳机插孔(){Lightning耳机。插Lightning接口()}}}电脑传统耳机插孔。Insertearphone(traditionalearphone)//插入传统耳机插孔成功电脑传统耳机插孔。Insertearphone(Lightningearphonetotraditionalearphoneadapter(Lightningearphone))//插入Lightning耳机接口成功代码实现回到一开始接口不匹配的问题,Table组件提供了一个responseProcessorhook,我们只需要包裹接口通过这个钩子返回的数据。{...responseProcessor(res){return{...res,msg:res.message,//出错时提示data:{...res.datalist:res?.data?.records||[],//表格列表}};},...}更多场景除了处理数据格式不一致,我们还可以通过适配器方式为上层提供统一的接口,解决兼容性问题。最典型的例子就是jQuery,可以看下其中一段代码://创建请求对象//(为了向后兼容,这仍然附加到ajaxSettings)jQuery.ajaxSettings.xhr=window.ActiveXObject!==undefined?//支持:IE6-IE8function(){//XHR无法访问本地文件,在这种情况下总是使用ActiveXif(this.isLocal){returncreateActiveXHR();}//支持:IE9-11//使用ActiveXXHR时,IE似乎在跨域PATCH请求上出错。在IE9+中始终使用原生XHR。//注意:此条件不会捕获Edge,因为它没有定义//document.documentMode但它也不支持ActiveX,因此它不会//??到达此代码。if(document.documentMode>8){返回createStandardXHR();}//支持:IE<9//oldIEXHR不支持非RFC2616方法(#13240)//请参见http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx//andhttp://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9//虽然这个检查对于六个方法而不是八个//因为IE也不支持“trace”和“connect”return/^(get|post|head|put|delete|options)$/i.test(this.type)&&createStandardXHR()||他们的用意不同:适配器模式是为了解决两个对象不匹配的问题,原始对象不适合直接修改。在这种情况下,可以使用适配器模式进行一层转换。代理模式是增强原有对象的功能,提供的接口不会改变。totaladapter模式是一种比较简单的设计模式,在js中自然会应用。一般可以通过函数进行转换。
