适配器模式详解

54 阅读3分钟

概述

适配器(Adapter Pattern)模式 主要用于接口互不兼容的类的协调工作。

适配器模式分为:

  • 类适配器模式
    • 实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。
  • 对象适配器模式
    • 实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。

前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

在什么情况下我们会需要适配器模式呢?

例如我们对接一个第三方接口A,A需要传参第三方提供的对象B,但是我的系统目前提供的对象为C,那么我便可以定义一个AdapterD,D继承B(或者实现B的接口),在D中聚合C,这样使用接口A时,就可以传入对象D(因为继承,属于B的一种),在D中实际调用的实现为C。

案例

假设我的原系统中拥有TD类,需要对接第三方接口Computer,但是Computer只能读取第三方携带的CD类,我要Computer从TD中读取数据,就需要定义CDAdapterTD适配器类来完成,具体代码实现如下:

public class Main {

    public static void main(String[] args) {
        //原系统中有的TD
        TD td = new TD();
        //第三方接口提供的Computer
        Computer computer = new Computer();
        //要让computer实际中TD中读取数据
        computer.readCD(new CDAdapterTD(td));
    }

}

class Computer{

    public void readCD(CD cd){
        System.out.println(cd.readCD());
    }

}
interface CD{
    String readCD();
}

class CDImpl implements CD{

    @Override
    public String readCD() {
        return "我是CD";
    }
}
class TD{
    public String readTD(){
        return "我是TD";
    }
}
class CDAdapterTD implements CD{

    public TD td;

    public CDAdapterTD(TD td){
        this.td = td;
    }

    @Override
    public String readCD() {
        return td.readTD();
    }
}

JDK源码解析

IO

在对于Reader字符流的实现中,使用了适配器模式。

背景:计算机系统存储文件是用二进制字节的形式存储的,jvm也只为我们提供了操作字节的native方法,所以,使用java实现读取字符,本质上是先读取字节,再通过解码生成字符。

因此,对于Reader的read实现来说,就必然会存在,调用inputstream去读取字节,再进行解码,生成字符这个流程。

还记得我上文概述说的适配器模式适用的情况吗?这里以此作为例子再说一遍。

现有系统拥有的是读取字节流的能力(InputStream),对接第三方接口需要传递一个读取字符流功能的能力,第三方接口给了我们一个Reader类,定义了规范,需要我们自己去实现。

因此我们定义类A继承Reader类,在类A中聚合InputStream,在重写的read方法中,先调用InputStream的read方法,再加上解码逻辑,这样就实现了Reader要求的读取字符流,这便是适配器模式。

而这个类A在java中的实现便是 StreamDecoder 。具体代码感兴趣可从FileReader一层一层往上看。