9-设计模式-适配器模式(设计模式学习笔记)

142 阅读4分钟

适配器模式

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

想要使用一个已经存在的对象,但是其方法或属性接口不符合我们的要求,所以需要对其进行适配。

例如:usb接口转换器

适配器模式中主要角色

目标(Target)角色:定义客户端使用的与特定领域相关的接口,这也就是我们所期待得到的。

源(Adaptee)角色:需要进行适配的接口。

适配器(Adapter)角色:对Adaptee的接口与Target接口进行适配;适配器是本模式的核心,适配器把源接口转换成目标接口,此角色为具体类。

适配器模式适用场景

1、你想使用一个已经存在的类,而它的接口不符合你的需求。

2、你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作。

3、你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)。

适配器的小例子

image.png

假设有一个香港版的插头,由于其插头样式怪异,无法插入内地的插座中,如果我们想要使用这个香港版插头,就需要一个适配器来进行适配。代码如下:

// 香港版插头
    class Plug{
        fn(){
            return "香港的插头"
        }
    }

    // 适配插头
    class Target{
        constructor() { // 旧的接口不能丢也不能修改
            this.plug = new Plug() // 这里是旧的接口:香港版插头
        }
        adaptePlug(){ // 这里就是进行适配,将旧的接口与新的接口进行适配
            return this.plug.fn() + "使用适配器,适配成为中国内地版插头" // 这里面写如何适配,适配的内容
        }
    }
    let gn = new Target() // new一个适配器
    gn.adaptePlug() // 适配器调用适配后的接口

适配器的原则及优缺点

不能影响原来的功能,也就是不能修改原来旧接口的代码

原来的功能要拿过来,在原来的基础上再去进行相关的适配和调整

优点:简单,复用性比较高

缺点:系统的层级复杂,会包装许多函数

适配器的具体用途

1.用适配器保证传入参数的完整性与顺序性:

    // 用适配器保证传入参数的完整性与顺序性:

    function doThing(name,title,age,color,size,flag){ //这个参数很多,万一传漏了或者传错位置就不好
        // 假设这是具体执行的操作
        return `${name}今年${age}岁,喜欢的颜色是${color},长度是${size},梦想是${flag}${title}`
    }

    // 上面的doThing函数,参数很多,如果我们要使用它,需要将参数一一对应,还不能漏传,极其不友好。
    // 我们要的结果是,哪怕我们的数据位置不一样或者漏传,用适配器也能保证参数不出问题

    var message = { // 这是我们需要接收的数据
        name:"remi",
        title:"小目标",
        age:18,
        color:"yellow",
        size:180,
        flag:"一个亿"
    }

    // 适配器
    function adaptDoThing(obj){

        // 默认的数据,如果没传或者漏传就用默认的参数数据
        var _adapt = {
            name:"张三",
            title:"不想努力了",
            age:99,
            color:"green",
            size:18,
            flag:"富婆,软饭,饿饿"
        }

        // 这一步才是真正的适配
        for(var i in _adapt){
            obj[i] = obj[i] || _adapt[i] // 用一个for in循环,实参要么等于形参(传了),要么等于默认的参数(没传)
        }

        return doThing(obj.name,obj.title,obj.age,obj.color,obj.size,obj.flag) // 此时我们对传入的参数进行适配,使其位置与原来的一一对应
    }

    console.log(adaptDoThing(message)) // 全部都传对了的情况

	var a = {name:"a"}
	console.log(adaptDoThing(a)) // 对象参数不齐的情况

2.适配器用于参数类型转换:

    // 适配器用于参数类型转换

    // 例如现在我们得到的一个数据是数组形式
    var arr = []
    arr.age = 18
    arr.name = "remi"
    arr.feature = "精壮"

    function arrToObj(arr){ // 适配器函数,数组转对象形式
        var newObj = {}
        for(var i in arr){
            newObj[i] = arr[i]
        }
        return newObj
    }
    var obj = arrToObj(arr)
    console.log(obj) // 这时候我们就能得到对象形式的数据

3.适配器用于代码兼容:

    // 适配器用于代码兼容
    
    // 有些浏览器是用new XMLHttpRequest()创建ajax对象,有些浏览器是用ActiveXObject("Microsoft.XMLHTTP")创建ajax对象
    function XMLHTTP(){
        if(window.ActiveXObject){ // 如果兼容这个则返回这个创建ajax
            return ActiveXObject("Microsoft.XMLHTTP")
        }else{ // 否则返回这个创建ajax
            return new XMLHttpRequest()
        }
    }

    XMLHTTP() // 创建ajax对象