本文转载自微信公众号「windliang」作者windliang。转载本文请联系windliang公众号。代码写了几年了,设计模式处于忘本忘读的状态。最近对设计模式有点感触,再学习总结一下。大多数关于设计模式的文章都使用基于类的静态类型语言,例如Java和C++。作为前端开发人员,js是一门基于原型的动态语言。职能已成为一等公民。模式略有不同,甚至简单得不像使用设计模式,有时会引起一些混淆。下面按照“场景”-“设计模式定义”-“代码实现”-“更多场景”-“通用”的顺序进行总结。如有不妥之处,欢迎交流讨论。在场景网络请求中,我们一般使用axios库,它支持Promise风格的调用。axios.get("/api/user",{params:{ID:"123",},}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});axios.post("/api/user",{firstName:"wind",lastName:"liang",},{headers:{"Content-Type":"application/json"},}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});可以看到上面传递的get和post参数是不统一的,使用起来会很麻烦,而且post需要手动传递headers。为了解决这些问题,我们可以通过外观(facade)模式来解决。查看外观(外观)模式的维基百科定义。★外观模式(也拼写为fa?ade)是面向对象编程中常用的一种软件设计模式。类比于建筑学中的门面,门面是一个对象,作为一个面向前端的接口,屏蔽更复杂的底层或结构代码外观模式相当于为一个相对复杂的界面或结构提供一个上层接口供用户使用.看一下UML类图。举个简单的例子,比如开机是一个复杂的过程,我们可以把它封装成一个函数来实现:/*复杂部分*/classCPU{publicvoidfreeze(){...}publicvoid跳转(长仓){...}publicvoidexecute(){...}}classMemory{publicvoidload(longposition,byte[]data){...}}classHardDrive{publicbyte[]read(longlba,intsize){...}}/*Fa?ade*/classComputer{publicvoidstartComputer(){cpu.freeze();memory.load(BOOT_ADDRESS,hardDrive.read(BOOT_SECTOR,SECTOR_SIZE));cpu.jump(BOOT_ADDRESS);cpu.execute();}}/*Client*/classYou{publicstaticvoidmain(String[]args){Computerfacade=newComputer();facade.startComputer();}}改写成js。算了,不改写了,哈哈,说白了,其实就是把几个函数封装成一个函数来调用。UML类图中的外观模式会和很多类进行交互,但是在js中可能很少遇到这种情况。通常当参数比较复杂或者某个函数使用起来比较麻烦的时候,我们可以通过外观模式来进行简化。代码实现回到最开始的axios的问题,我们可以把axios封装一层。//要求。jsimportaxiosfrom'axios';exportconstget=function(url,params){返回axios。得到(网址,{参数});};exportconstpost=function(url,params){返回axios。post(url,{...params},{headers:{"Content-Type":"application/json"}});};然后参考request.js调用。import{get,post}from"./request";get("/api/user",{ID:"123",}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});post("/api/user",{firstName:"wind",lastName:"liang",}).then(function(response){console.日志(响应);}).catch(函数(错误){console.log(错误);});多说一句:上面的封装只是为了演示外观模式的使用,在实际项目中通过外观模式进行封装会更加全面除了简化我们的调用之外,还有一个好处就是封装了底层的调用。如果以后底层需要改动,比如上面的axios换成fetch,我们只需要修改request.js,业务端不需要感知。更广泛地说,场景外观模式是为了更容易将复杂的调用包裹在一层中。我们平时使用的Vue的模板和React的jsx也可以认为是使用了外观模式。它们都封装了底层dom的创建,方便我们写页面。前面提到的混合设计模式中的代理模式、适配器模式、模板方法、外观模式,在结构上看起来都很相似。区别在于他们的用意不同:适配器模式是为了解决两个对象之间的不匹配问题。但是,原始对象不适合直接修改。在这种情况下,可以使用适配器模式进行一层转换。代理模式是增强原有对象的功能,提供的接口不会改变。模板模式是将不同的功能组合在一起,只提供框架,具体的实现需要调用者传入。外观模式是为了封装更复杂的调用,提供新的接口给用户使用。整体外观模式是一种比较自然的设计模式。如果觉得某个功能太麻烦、太频繁使用,自然会想到封装一层再使用。外观模式的另一个好处是它可以更好地响应未来的底层变化。
