设计模式 结构型模式 -- 适配器模式(概述类适配器模式对象适配器模式适配器模式适用场景JDK源码解析(I / O流))

Posted Z && Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 结构型模式 -- 适配器模式(概述类适配器模式对象适配器模式适配器模式适用场景JDK源码解析(I / O流))相关的知识,希望对你有一定的参考价值。

1. 适配器模式


1.1 引入



1.2 定义

  • 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  • 适配器模式分为类适配器模式(使用的是继承的方式)和对象适配器模式(使用聚合或者组合的方式),前者类之间的耦合度比后者高,且类适配器模式要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

1.3 结构

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

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

适配器模式的结构(类适配器):

适配器模式的结构(对象适配器):

典型的类适配器代码:

典型的对象适配器代码:


1.4 实例说明

需求:

类图:

类说明:


2. 类适配器模式

实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。


2.1 【例】读卡器分析:

现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器,将TF卡中的内容读取出来。


2.2 【例】读卡器实现:

实现方式:定义一个适配器类来实现当前系统的业务接口(SDCard),同时又继承现有组件库中已经存在的组件(TFCardImpl)。


2.2.1 TFCard

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: TFCard
 * @Description: 适配者类的接口
 */
public interface TFCard {

    //从TF卡中读取数据
    String readTF();

    //往TF卡中写数据
    void writeTF(String msg);
}

2.2.2 TFCardImpl

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: TFCardImpl
 * @Description: 适配者类
 */
public class TFCardImpl implements TFCard {

    public String readTF() {
        String msg = "TFCard read msg : hello word TFcard";
        return msg;
    }

    public void writeTF(String msg) {
        System.out.println("TFCard write msg :" + msg);
    }
}

2.2.3 SDCard

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: SDCard
 * @Description: 目标接口
 */
public interface SDCard {

    //从SD卡中读取数据
    String readSD();

    //往SD卡中写数据
    void writeSD(String msg);
}

2.2.4 SDCardImpl

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: SDCardImpl
 * @Description: 具体的SD卡(目标接口实现类)
 */
public class SDCardImpl implements SDCard {

    public String readSD() {
        String msg = "SDCard read msg : hello word SD";
        return msg;
    }

    public void writeSD(String msg) {
        System.out.println("SDCard write msg :" + msg);
    }
}

2.2.5 Computer

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: Computer
 * @Description: 计算机类(可以用计算机调用SD卡的读写方法)
 */
public class Computer {

    //从SD卡中读取数据
    public String readSD(SDCard sdCard) {
        if (sdCard == null) {
            throw new NullPointerException("sd card can not be null");
        }
        return sdCard.readSD();
    }
}

2.2.6 SDAdapterTF

配器类(SD卡适配TF卡) 需要类来实现当前系统的业务接口(SDCard),同时又继承现有组件库中已经存在的组件(TFCardImpl)。

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: SDAdapterTF
 * @Description: 适配器类(SD卡适配TF卡) 需要类
 * 来实现当前系统的业务接口(SDCard),同时又继承现有组件库中已经存在的组件(TFCardImpl)。
 */
public class SDAdapterTF extends TFCardImpl implements SDCard {

    public String readSD() {
        System.out.println("adapter read tf card");
        return readTF();
    }

    public void writeSD(String msg) {
        System.out.println("adapter write tf card");
        writeTF(msg);
    }
}

2.2.7 Client

package com.tian.adapter.class_adapter;

/**
 * @version v1.0
 * @ClassName: Client
 * @Description: 客户端类(适配器类)
 */
public class Client {
    public static void main(String[] args) {
        //创建计算机对象
        Computer computer = new Computer();
        //读取SD卡中的数据
        String msg = computer.readSD(new SDCardImpl());
        System.out.println(msg);

        System.out.println("===============");
        //使用该电脑读取TF卡中的数据
        //定义适配器类
        String msg1 = computer.readSD(new SDAdapterTF());
        System.out.println(msg1);
    }
}

2.2.8 运行结果:


2.3 类适配器模式分析

类适配器模式违背了合成复用原则(优先使用对象组合, 而不是通过继承来达到复用的目的)。类适配器是客户类有一个接口规范(例如本例中的:SDCard)的情况下可用,反之不可用。


3. 对象适配器模式

实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。


3.1 【例】读卡器

我们使用对象适配器模式将读卡器的案例进行改写。类图如下:


3.2 【例】读卡器实现

  • 实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中(SDAdapterTF),该类同时实现当前系统的业务接口(SDCard)。
  • 类适配器模式的代码,我们只需要修改适配器类(SDAdapterTF)和测试类。

3.2.1 SDAdapterTF

package com.tian.adapter.object_adapter;

/**
 * @version v1.0
 * @ClassName: SDAdapterTF
 * @Description: 适配器类:
 * 将现有组件库中已经实现的组件(TFCard)引入适配器类中,该类同时实现当前系统的业务接口(SDCard)。
 */
public class SDAdapterTF implements SDCard {

    //声明适配者类
    private final TFCard tfCard;

    public SDAdapterTF(TFCard tfCard) {
        this.tfCard = tfCard;
    }

    public String readSD() {
        System.out.println("adapter read tf card");
        return tfCard.readTF();
    }

    public void writeSD(String msg) {
        System.out.println("adapter write tf card");
        tfCard.writeTF(msg);
    }
}

3.2.2 Client

package com.tian.adapter.object_adapter;


/**
 * @version v1.0
 * @ClassName: Client(客户端类 : 适配器类)
 */
public class Client {
    public static void main(String[] args) {
        //创建计算机对象
        Computer computer = new Computer();
        //读取SD卡中的数据
        String msg = computer.readSD(new SDCardImpl());
        System.out.println(msg);

        System.out.println("===============");
        //使用该电脑读取TF卡中的数据
        //创建适配器类对象
        SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImpl());
        String msg1 = computer.readSD(sdAdapterTF);
        System.out.println(msg1);
    }
}

3.2.3 运行结果(其余的代码不用改动)


3.3 说明

注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可。


4. 适配器模式适用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

5. JDK源码解析(I / O流)

Reader(字符流)、InputStream(字节流)的适配使用的是InputStreamReader。InputStreamReader继承自java.io包中的Reader,对他中的抽象的未实现的方法给出实现。如:

        public int read () throws IOException {
            return sd.read();
        }
        public int read ( char cbuf[], int offset, int length) throws IOException {
            return sd.read(cbuf, offset, length);
        }

如上代码中的sd(StreamDecoder类对象),在Sun的JDK实现中,实际的方法实现是对sun.nio.cs.StreamDecoder类的同名方法的调用封装。类结构图如下:

从上图可以看出:

  • InputStreamReader是对同样实现了ReaderStreamDecoder的封装。
  • StreamDecoder不是Java SE API中的内容,是Sun JDK给出的自身实现。但我们知道他们对构造方法中的字节流类(InputStream)进行封装,并通过该类进行了字节流和字符流之间的解码转换。

结论:

从表层来看,InputStreamReader做了InputStream字节流类到Reader字符流之间的转换。而从如上Sun JDK中的实现类关系结构中可以看出,是StreamDecoder的设计实现在实际上采用了适配器模式。

补充:

  • Decoder(解码):字节流数据 转换为 字符流数据。
  • 编码:字符流数据 转换为 字节流数据


以上是关于设计模式 结构型模式 -- 适配器模式(概述类适配器模式对象适配器模式适配器模式适用场景JDK源码解析(I / O流))的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 - 结构型模式_适配器模式

设计模式 - 结构型模式_适配器模式

适配器模式

适配器模式

Java设计模式之适配器模式

设计模式 结构型模式 -- 结构型模式(代理模式适配器模式装饰者模式桥接模式外观模式组合模式享元模式)