• Java适配器模式源码剖析及使用场景


    一、适配器模式介绍

    适配器模式(Adapter Pattern)是一种结构型设计模式,它作用于将一个类的接口转换成客户端所期望的另一种接口,从而使原本由于接口不兼容而无法一起工作的那些类可以在一起工作。它属于包装模式的一种。

    适配器模式主要分为两种:

    • 类适配器: 通过继承的方式实现适配器功能
    • 对象适配器: 通过组合的方式实现适配器功能

    二、大白话理解

    适配器模式可以用生活中的插座转换器来理解。我们都知道,不同国家或地区使用的插座类型不尽相同。当你从国内带着笔记本电脑出国旅行时,由于插座类型的不同,可能无法为笔记本供电。这时就需要使用一个插座转换器,将你的笔记本电源插头适配到当地的插座上。这个转换器,就是一个很好的适配器模式实例。

    在这个例子中:

    • 笔记本电脑的电源插头就是"被适配者"
    • 当地的插座就是"目标接口"
    • 插座转换器就是"适配器"

    三、 项目案例

    假设我们有一个第三方的老式圆孔接口 LegacyRoundHole 和一个新式方形接口 NewSquarePeg。现在需要将新式方形接口适配到老式圆孔接口上。我们可以通过创建一个适配器类 SquarePegAdapter 来实现适配,代码如下:

    // 老式圆孔接口
    interface LegacyRoundHole {
        void insertRoundPeg(RoundPeg peg);
    }
    
    // 新式方形接口
    interface NewSquarePeg {
        void insertSquarePeg();
    }
    
    // 适配器(对象适配器方式)
    class SquarePegAdapter implements LegacyRoundHole {
        private NewSquarePeg squarePeg;
    
        public SquarePegAdapter(NewSquarePeg squarePeg) {
            this.squarePeg = squarePeg;
        }
    
        @Override
        public void insertRoundPeg(RoundPeg peg) {
            // 通过一些算法将方形适配到圆孔
            squarePeg.insertSquarePeg();
        }
    }
    
    // 适配器(类适配器方式)
    class SquarePegClassAdapter extends RoundPeg {
        private NewSquarePeg squarePeg;
    
        public SquarePegClassAdapter(NewSquarePeg squarePeg) {
            this.squarePeg = squarePeg;
        }
    
        @Override
        public void insertIntoHole(LegacyRoundHole hole) {
            // 通过一些算法将方形适配到圆孔
            squarePeg.insertSquarePeg();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在上面的代码中,我们分别使用对象适配器和类适配器的方式实现了适配器模式。

    • SquarePegAdapter 实现了旧接口 LegacyRoundHole,同时在内部持有一个新接口 NewSquarePeg 对象。当客户端调用 insertRoundPeg 方法时,适配器就会将请求转发给新接口对象,并通过一些算法进行适配。
    • SquarePegClassAdapter 继承了 RoundPeg 类,同时在内部持有一个新接口 NewSquarePeg 对象。当客户端调用 insertIntoHole 方法时,适配器就会将请求转发给新接口对象,并通过一些算法进行适配。

    这样就实现了新旧接口的兼容。

    四、Java源码

    在Java源码中,适配器模式也有典型的应用,比如 java.util.Arrays#asList()

    List<String> strs = Arrays.asList("a", "b", "c");
    
    • 1

    asList() 方法会返回一个包装好的 ArrayList 对象,里面装了传入的数组元素。这里 Arrays 类就相当于适配器,将基本的数组适配成了 List 类对象。

    另一个例子是 java.io.InputStreamReaderjava.io.OutputStreamWriter:

    Reader reader = new InputStreamReader(new FileInputStream("file.txt"), "UTF-8");
    Writer writer = new OutputStreamWriter(new FileOutputStream("file.txt"), "UTF-8");
    
    • 1
    • 2

    这两个类将低级的字节流适配成高级的字符流,屏蔽了字节与字符编码转换层的底层细节。InputStreamReaderOutputStreamWriter 起到了适配器的作用。

    InputStreamReader 的源码中,我们可以看到它是如何将字节流适配成字符流的:

    public class InputStreamReader extends Reader {
        
        private final StreamDecoder sd;
    
        public InputStreamReader(InputStream in, String charsetName) {
            super(in);
            try {
                sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
            } catch (UnsupportedEncodingException uee) {
                throw new UnsupportedCharsetException(uee.getMessage());
            }
        }
    
        public int read() throws IOException {
            return sd.read();
        }
    
        // 其他方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    可以看到,InputStreamReader 内部持有一个 StreamDecoder 对象,它负责将字节解码成字符。当我们调用 read() 方法时,实际上是委托给 StreamDecoder 去读取和解码字节流。

    适配器模式非常实用,在实际开发中经常会遇到接口不兼容的情况,通过使用适配器模式就可以让这些原本不兼容的类一起工作。

  • 相关阅读:
    接口测试测什么?这篇文章告诉你
    【Python】手把手教你——如何生成属于自己的二维码 ~
    分布式锁之 redis & redisson (你学了 synchronized 真的有用吗?)
    Spring学习篇(三)
    python实操-----图书管理系统
    python制作动态字符画(简单易上手版)
    干了外包3个月,技术退步明显...
    数字孪生扫除智慧城市“盲点”,赋能社会数字发展
    python web框架哪家强?Flask、Django、FastAPI对比
    代码随想录算法训练营第一天 | 704. 二分查找 | 27. 移除元素
  • 原文地址:https://blog.csdn.net/weixin_44716935/article/details/136563862