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();
    }
}

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

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

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

四、Java源码

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

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

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");

这两个类将低级的字节流适配成高级的字符流,屏蔽了字节与字符编码转换层的底层细节。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();
    }

    // 其他方法
}

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

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

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
适配器模式是一种结构型设计模式,它允许将不兼容的对象组合在一起,通过适配器来使其能够正常工作。在Java编程语言中,适配器模式通常用于将现有接口转换为客户端所期望的接口。 下面是一个Java适配器模式的例子,假设我们有一个已经存在的类,该类只能输出字符串,但我们需要输出整数。我们可以使用适配器模式来解决这个问题。 首先,我们定义一个接口,该接口定义了我们期望的输出整数的方法: ``` public interface IntegerOutput { public int outputInt(); } ``` 然后,我们创建一个适配器类,该类实现了这个接口,并将字符串转换为整数输出: ``` public class StringToIntegerAdapter implements IntegerOutput { private String str; public StringToIntegerAdapter(String str) { this.str = str; } public int outputInt() { int intValue = Integer.parseInt(str); return intValue; } } ``` 最后,我们使用适配器类来输出整数: ``` public class Main { public static void main(String[] args) { String str = "123"; IntegerOutput adapter = new StringToIntegerAdapter(str); int intValue = adapter.outputInt(); System.out.println(intValue); } } ``` 在这个例子中,我们使用适配器模式将不兼容的字符串转换为整数输出。通过创建一个适配器类,该类实现了期望的输出整数的接口,并将字符串转换为整数输出。最后,我们使用适配器类来输出整数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java语录精选

你的鼓励是我坚持下去的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值