概念
适配器模式: 将一个类(对象)的接口( 方法或者属性 )转化成另外一个接口,以满足客户需求。使类(对象)之间的接口的不兼容问题得到解决
在生活中也有很多类似的例子,比如有的手机没有3.5耳机插口,所以就需要增加一个转接头来完成适配功能以确保耳机的正常使用,如下图:
在我们平时开发中如果是我们自己定义的方法,去直接修改代码即可。但是有很多情况我们回去使用第三方的库暴露出来的 api,这个时候我们就没办法去直接修改他的代码,所以我么需要一种来方法来做适配。
适配数据
假设我有一个对象 obj,我需要它能够适配函数 interfaceMethod:
var obj = {
name:"黑黑的脸蛋",
age:"23",
address:"China"
}
function interfaceMethod( name,age,address ) {
// ...
}
但是我们从代码上面来看,interfaceMethod 函数并不能够直接适配 obj 对象,这是我们就需要一个适配器来来达到我们的目的。
function objTointerfaceAdapter( params ) {
interfaceMethod( params.name, params.age, params.address )
}
// 利用适配器来传递对象
objTointerfaceAdapter( obj )
可见,通过使用适配器,我们既不用改对象结构,又不用改现有的方法,就达到了目的。
浏览器的事件绑定
在不同的浏览器中我们去绑定事件写法是不同的,如果我们只写 addEventLister 去实现事件绑定,那在其他平台中,我们的代码就会抛出异常。我们可以使用适配器的方法,来适配多种浏览器的事件绑定:
function BindEventListerAdapter( ele, event, callback ) {
// 普通浏览器的事件绑定
if( ele.addEventLister ) {
ele.addEventLister( event, callback )
}
// IE 浏览器事件绑定
else if( ele.attachEvent ) {
ele.attachEvent( "on" + event, callback )
}
// 其他平台的事件绑定
else {
ele[ "on" + event ] = callback
}
}
适配 Jquery
比如我在我的代码中去实现了 ajax 方法:
ajax({
// ...
})
但是因为项目需求,我们引入了 Jquery 第三方库,而使用 ajax 方法的时候就会这样:
$.ajax({
// ...
})
这是两种不同的写法,我们并不能保证我们的代码会一直使用 Jquery,如果有一天我们不去使用这个库的时候,那他的 ajax 方法就不存在了,又用回来了我们自己的 ajax。但是这两种写法无论是需求的改变还是考虑未来,我们都因该去适配它:
var $ = {
ajax:function(){
// ...
}
}
Vue 中的 computed
Vue 中的 computed 就体会了这一思想:
<template>
<span> {{ reversedMessage }} </span>
</template>
<script>
export default {
data:() => ({
message:"Hello"
}),
computed:{
reversedMessage:function() {
return this.message.split("").reverse().join("")
}
}
}
</script>
message 这个属性的值是 Hello,但我想要的是一个倒转的 Hello, 通过computed 中的 reversedMessage 方法, 我们得到了目标 olleh,且没有改变原有的数值。这里的 reversedMessage 就相当于一个适配器。
使用场景
- 使用一个已经存在的对象,但其方法或属性不符合我们的要求。
- 统一多个对象的接口
- 适配不同格式的数据
- 同时兼容新老版本
总结
在传统的设计模式中,适配器通常解决两个类接口不兼容的问题。然而在 JavaScrit 中使用更广泛,比如适配不同的库,数据格式等等。
JavaScript 中的适配器模式,更多在对象之间,为了对象可用通常我们会把对象拆分并重新包装,这样我们就需要全面了解对象的内部结构。同时适配器也解决了对象之间的耦合度,虽然在适配器中加入了一些代码增加了资源开销,但是这些都是微乎其微的。