适配器模式


定义

适配器,其实很好理解,生活中也随处可见,比如电源适配器、usb 适配器等等,那么适配器模式,也被称为Wrapper 模式。

Wrapper 有“包装器”的意思,适配器模式的定义是:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,解决的痛点便是因接口不兼容导致的类不能正常工作的问题。

如上图所示,A、B 代表已经塑模成型的物体 A 和 B,如果想将这两种物体安装在一起,因为两者的接口是不兼容的,不可能直接安装在一起,这个时候该怎么办?这里,我们可以引入物体 C,物体 C 既要适配 A 的接口,又要适配 B 的接口,经过 C 的无缝“衔接”,便将 A、B 完美结合在了一起。

这里的物体 C 就是我们要说的适配器角色,起到了一定的角色转换的作用。再举个例子,如果想让直流 12v 的笔记本电脑工作在交流 220v 的电源下,就必须要一个电源适配器,该适配器的作用就是将 220v 的 AC 交流转为 12v 的 DC 直流,这就是适配器该干的工作,弥补两者之间的空白——承上启下。

什么时候使用适配器模式,从上面的案例我们也可以看出一点端倪:

  • 现有的类或接口不能满足需求,且一般无法直接修改现有类或接口。比方该类为三方提供,就无法修改,亦或者像A、B 这种已经塑模成型的物件,可能已大规模在使用中,所以不允许修改。
  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。

组成角色

适配器模式,根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

适配器模式的通用类图如下:

适配器模式包含的角色如下:

  • 目标角色(Target):该角色定义把其它类转换为何种接口,也就是我们的期望接口,可以是一个抽象类或接口,也可以是具体类。以上文中笔记本电脑为例,即指让笔记本正常工作的直流 12v 电源;
  • 适配器角色(Adapter):适配器可以调用另一个接口,作为一个转换器,对 Adaptee 和 Target 进行适配,适配器类是适配器模式的核心,通常都是一个具体的类。以上文中笔记本电脑为例,即指电源适配器;
  • 源角色(被适配 Adaptee ):你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象,经过适配器角色的包装,它会成为一个崭新、靓丽的角色。以上文中笔记本电脑为例,即指 220v 的 AC 电源;
  • 请求者(Client):该角色负责使用 Target 定义的方法进行具体处理,以上文中笔记本电脑为例,即指使用 12v 电源驱动的笔记本电脑。

总的一句话,Adapter 就是一个在 Client 中使用 Target 定义的接口来使用 Adaptee 角色(调用 Adaptee 中的方法)的存在。

类适配器(使用继承)

如上图为使用类适配器实现的适配器模式,具体代码如下:

首先是 Target 接口,也就是我们要适配的目标接口:

public interface Target {

    public abstract void targetMethod1();

    public abstract void targetMethod2();
}

接下来是要被适配的“接口”,即 Adaptee:

public class Adaptee {

    public void methodA() {
        System.out.println("Adaptee methodA invoked.");
    }

    public void methodB() {
        System.out.println("Adaptee methodB invoked.");
    }

}

然后是我们的适配器,关键代码如下:

public class Adapter extends Adaptee implements Target{

    @Override
    public void targetMethod1() {
        System.out.println("Adapter targetMethod1 inkoked.");
        methodA();
    }

    @Override
    public void targetMethod2() {
        System.out.println("Adapter targetMethod2 inkoked.");
        methodB();
    }
}

最后是我们的 Client,在这里就是 Main 类:

public class Main {

    public static void main(String[] args) {

        // 通过Adapter继承Adaptee实现了Adaptee角色的调用
        Target target = new Adapter();
        target.targetMethod1();
        target.targetMethod2();

    }
}

执行结果如下:

Adapter targetMethod1 inkoked.
Adaptee methodA invoked.
Adapter targetMethod2 inkoked.
Adaptee methodB invoked.

这里,Client 使用者并不知道 Adaper 适配器是如何工作的,就好比笔记本电脑只需要在 12v 电压下正常工作即可,具体适配器如何适配实现电压转换,笔记本电脑无需关心。

对象适配器(使用委托)

如上图为使用对象适配器实现的适配器模式,具体代码如下:
首先是我们要适配的目标类,这里不是接口了注意:

public abstract class Target {

    public abstract void targetMethod1();

    public abstract void targetMethod2();

}

因为 java 的类不支持多继承,但是在单继承模式下我们可以使用委托来实现方法的调用,修改后的 Adapter 适配器代码如下:

public class Adapter extends Target{

    private Adaptee adaptee;

    public Adapter() {
        this.adaptee = new Adaptee();
    }

    @Override
    public void targetMethod1() {
        System.out.println("Adapter targetMethod1 inkoked.");
        adaptee.methodA();
    }

    @Override
    public void targetMethod2() {
        System.out.println("Adapter targetMethod2 inkoked.");
        adaptee.methodB();
    }
}

Client 调用的时候没有变化,还是如下:

public static void main(String[] args) {

    // 通过Adapter使用委托,实现了Adaptee角色的调用
    Target target = new Adapter();
    target.targetMethod1();
    target.targetMethod2();

}

输出结果:

Adapter targetMethod1 inkoked.
Adaptee methodA invoked.
Adapter targetMethod2 inkoked.
Adaptee methodB invoked.

优缺点

主要优点:

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构;
  • 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用;
  • 可以将两个互不相干的类关联在一起;
  • 增强系统灵活性。

主要缺点:

  • 类适配器对于 Java、C# 等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者。

应用场景

类适配器与对象适配器的使用场景一致,主要应用于如下场景:

  • 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码,这时创建一个适配器就能间接去改造这个类中的方法;
  • 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

总结

适配器模式,本身属于一种结构型模式,用于在两个对象或者系统之间建立适配链接,使得前后系统衔接更加平滑,适配器模式的实现主要有继承方式的类适配器,和委托方式的对象适配器。


Author: Re:0
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Re:0 !
 Previous
桥接模式 桥接模式
定义桥接模式 (Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体 (Handle and Body) 模式或接口 (Interface) 模式。
2022-03-08
Next 
原型模式 原型模式
设计一个类的时候,我们通常会使用到构造函数,这里类和对象的关系好比模具和构件的关系,对象总是从类中创建的。但是某些场景下是不允许类的调用者直接调用构造函数,也就说对象未必需要从类中衍生出来,现实生活中存在太多案例是通过直接 “克隆” 来产生
2022-03-07
  TOC