一、解释
适配器模式可用来在现有接口和不兼容的类之间进行适配。它被添加到现有代码中来协调两个不同的接口。就类似于苹果电脑的 type-c 接口和U盘之间的接口转换器。
二、举例
🌰1 :来看一个简单的例子
我们现在客户系统有一个对象 clientObj,而我们有一个现有的方法 interfaceMethod:
var clientObj = {
name: 'Jack',
phone: '13333333333',
address: 'China'
}
function interfaceMethod(str1, str2, str3){
...
}
这时要把 clientObj 作为参数传给这个方法,需要一个适配器:
function clientToInterfaceAdapter(o) {
interfaceMethod(o.name, o.phone, o.address)
}
// 利用适配器传递对象
clientToInterfaceAdapter(clientObj)
可见,通过使用适配器,我们既不用改对象结构,又不用改现有的方法,就达到了目的。
🌰2:适配器模式在实际项目中的应用
比如我用 jQuery 封装 ajax,调用方式:
$.ajax({
...
})
但我现在不用 jQuery 了,并且我自己写了一个 ajax,调用方式:
ajax({
...
})
那么问题来了,以前的写法都不适用了,我要全局搜索把“$"去掉吗?这样不仅费时费力,万一删错了就麻烦了。
所以为了兼容旧的代码,我们决定写一个适配器:
var $ = {
ajax: function(options){
return this.ajax(options);
}
}
🌰3:适配器模式在 vue 中的应用
vue 的 computed 中体现了这一思想:
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
message 这个属性的值是 'Hello',但我想要的是一个倒转的 'Hello', 通过computed 中的 reversedMessage 方法, 我们得到了目标 'olleh',且没有改变原有的数值。这里的 reversedMessage 就相当于一个适配器。
🌰4:适配器模式在 ts 中的应用
type Person = {
name: string,
age: number
}
const jack: Person = {
name: 'Jack',
age: 11
}
如果这个时候,我只想定义name或者age要怎么做?可以把上面的Person改成:
type Person = {
name?: string,
age?: number
}
加上‘?’,表示这个属性可选。但这样真的好吗?如果我们引用的是第三方的库,或者我们改动了代码不够严谨了,那怎么办?考虑到这些,我们建议不直接修改。这个时候 ts 的 utility type 帮我们解决了这个问题。
const jack: Partial<Person> = {} // 直接这样写就行了
我们来看 ts 关于 Partial 的源码,遍历 Person 里面的 key,给每个 key 加上‘?’
type Partial<T> = {
[P in keyof T]?: T[P];
};
这个 Partial 的使用就是适配器的思想。
三、适用场合
1、该模式适用于期待接口与现在接口不兼容。
2、适配器所适配的两个方法执行需是类似的任务。
3、接口最好是成形的。如果新接口或者现有的老接口没有成型,那么适配器不会一直管用,就失去了它的意义。
四、总结
当我们需要用原有代码,但需要有一定的改动。最好不直接去改动,因为可能大规模改写现有代码,也可能会因此导致原有代码出现问题。所以建议封装一个方法。