前端必懂的设计模式-门面模式

网站建设4年前发布
10 0 0

外观模式(Facade Pattern)又叫门面模式,指提供一个统一的接口去访问多个子系统的多个不同的接口,为子系统中的一组接口提供统一的高层接口。使得子系统更容易使用,不仅简化类中的接口,而且实现调用者和接口的解耦。,该设计模式由以下角色组成,外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合 子系统角色:实现了子系统的功能。它对客户角色和Facade是未知的。,实现了子系统的功能。它对客户角色和Facade是未知的,通过调用Facede来完成要实现的功能,20230306131921d1b83507099098682e016797e48316cad0964f143,门面模式类图,比如常见的空调、冰箱、洗衣机,内部结构都并不简单,对于我们使用者而言,理解他们内部的运行机制的门槛比较高,但是理解遥控器/控制面板上面寥寥几个按钮就相对容易的多,这就是外观模式的意义。,202303061322188894c6a27c7f3ec5a1202199fbab0fbb55ba95427,遥控器,在类似场景中,这些例子有以下特点:,一个统一的外观为复杂的子系统提供一个简单的高层功能接口。 原本访问者直接调用子系统内部模块导致的复杂引用关系,现在可以通过只访问这个统一的外观来避免。,在外观模式中,客户端直接对接外观(Facade),通过接口去对接子接口,而子接口里封装的一系列复杂操作,则不是我们要关注的重点。,结构如下:,20230306132309991217899f37c3a9a73269597f16906a3b0cf9468,202303061319226949793560a68f29e29927d9c554fc67e712a4973,20230306132220f268a4f9493c5fe1d243776ee6f0cf4f3c5860161,有一种情况,比如某个函数有多个参数,其中一个参数可以传递也可以不传递,你当然可以直接弄两个接口,但是使用函数参数重载的方式,可以让使用者获得更大的自由度,让两个使用上基本类似的方法获得统一的外观。,上面这个绑定事件的函数中,参数 selector 就是可选的。,这种方式在一些工具库或者框架提供的多功能方法上经常得到使用,特别是在通用 API 的某些参数可传可不传的时候。,参数重载之后的函数在使用上会获得更大的自由度,而不必重新创建一个新的 API,这在 Vue、React、jQuery、Lodash 等库中使用非常频繁。,polyfill可以让我们处理浏览器兼容和屏蔽了浏览器差异。,外观模式经常被用于 JavaScript 的库中,封装一些接口用于兼容多浏览器,让我们可以间接调用我们封装的外观,从而屏蔽了浏览器差异,便于使用。,比如经常用的兼容不同浏览器的事件绑定方法:,除了事件绑定之外,在抹平浏览器兼容性的其他问题上我们也经常使用外观模式:,通过将处理不同浏览器兼容性问题的过程封装成一个外观,我们在使用的时候可以直接使用外观方法即可,在遇到兼容性问题的时候,这个外观方法自然帮我们解决,方便又不容易出错。,Vue 提供的一个创建元素的方法 createElement (opens new window)就使用了函数参数重载,使得使用者在使用这个参数的时候很灵活:,createElement 方法里面对第三个参数 data 进行了判断,如果第三个参数的类型是 array、string、number、boolean 中的一种,那么说明是 createElement(tag [, data], children, ...) 这样的使用方式,用户传的第二个参数不是 data,而是 children。,data 这个参数是包含模板相关属性的数据对象,如果用户没有什么要设置,那这个参数自然不传,不使用函数参数重载的情况下,需要用户手动传递 null 或者 undefined 之类,参数重载之后,用户对 data 这个参数可传可不传,使用自由度比较大,也很方便。,createElement方法的源码参见 Github 链接vue/src/core/vdom/create-element.js,Lodash 的 range 方法的 API 为 _.range([start=0], end, [step=1]),这就很明显使用了参数重载,这个方法调用了一个内部函数 createRange:,意思就是,如果没有传第二个参数,那么就把传入的第一个参数作为 end,并把 start 置为默认值。,createRange 方法的源码参见 Github 链接
lodash/.internal/createRange.js,函数参数重载在源码中使用比较多,jQuery 中也有大量使用,比如 on、off、bind、one、load、ajaxPrefilter 等方法,这里以 off 方法为例,该方法在选择元素上移除一个或多个事件的事件处理函数。源码如下:,可以看到如果传入第二个参数为 false 或者是函数的时候,就是 off(types [, fn]) 的使用方式。,off 方法的源码参见 Github 链接 jquery/src/event.js,再比如 load 方法的源码:,可以看到 jQuery 对第二个参数进行了判断,如果是函数,就是 load(url [, callback]) 的使用方式。,load 方法的源码参见 Github 链接 jquery/src/ajax/load.js(opens new window),当我们使用 jQuery 的 $(document).ready(...) 来给浏览器加载事件添加回调时,jQuery 会使用源码中的 bindReady 方法:,通过这个方法,jQuery 帮我们将不同浏览器下的不同绑定形式隐藏起来,从而简化了使用。,bindReady 方法的源码参见 Github 链接 jquery/src/core.js,除了屏蔽浏览器兼容性问题之外,jQuery 还有其他的一些其他外观模式的应用:,比如修改 css 的时候可以 $('p').css('color', 'red'),也可以 $('p').css('width', 100),对不同样式的操作被封装到同一个外观方法中,极大地方便了使用,对不同样式的特殊处理(比如设置 width 的时候不用加 px)也一同被封装了起来。,源码参见 Github 链接 jquery/src/css.js,再比如 jQuery 的 ajax 的 API ``$.ajax(url [, settings]),当我们在设置以 JSONP 的形式发送请求的时候,只要传入 dataType: 'jsonp' 设置,jQuery 会进行一些额外操作帮我们启动 JSONP 流程,并不需要使用者手动添加代码,这些都被封装在 $.ajax() 这个外观方法中了。,源码参见 Github 链接 jquery/src/ajax/jsonp.js,Axios 可以使用在不同环境中,那么在不同环境中发送 HTTP 请求的时候会使用不同环境中的特有模块,Axios 这里是使用外观模式来解决这个问题的:,这个方法进行了一个判断,如果在 Nodejs 的环境中则使用 Nodejs 的 HTTP 模块来发送请求,在浏览器环境中则使用 XMLHTTPRequest 这个浏览器 API。,getDefaultAdapter 方法源码参见 Github 链接 axios/lib/defaults.js,createStore,不符合单一职责原则和开放封闭原则,因此谨慎使用,不可滥用,优点:,缺点:,有时候一个系统只需要一个外观,比如之前举的 Axios 的 HTTP 模块例子。这时我们可以将外观模式和单例模式一起使用,把外观实现为单例。,文章出自:​​peffy​​,如有转载本文请联系前端餐厅ReTech今日头条号。,github:https://github.com/zuopf769,20230306131924a330a436120317f63b27207ea050f4fe18a241798,

© 版权声明

相关文章