一文搞懂设计模式—适配器模式

本文已收录至Github,推荐阅读 👉 Java随想录

微信公众号:Java随想录

适配器模式(Adapter Pattern)属于结构型模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的类之间进行合作,使得原本因接口不匹配而无法工作的类能够协同工作。

使用场景

适配器模式在以下情况下特别有用:

  • 当你想使用一个已经存在的类,但其接口与你的需求不匹配时。
  • 当你想创建一个可复用的类,该类与其他不相关的类或不可预见的类进行交互。
  • 当我们有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

实现方式

适配器模式的实现通常涉及三个角色:目标接口、适配器和被适配者。

  • 目标接口:定义了客户端需要使用的方法,是客户端期望的接口。
  • 适配器:实现了目标接口,并包含一个对被适配者的引用。通过对被适配者的调用来完成客户端请求。
  • 被适配者:已经存在的类或接口,与目标接口不兼容。

在 Java 中,一个常见的使用适配器模式的例子是InputStreamReader类。该类是Java I/O库中用于将字节流(InputStream)适配成字符流(Reader)的适配器。

java 复制代码
FileInputStream fis = new FileInputStream("hello world");
InputStreamReader adapter = new InputStreamReader(fis);
BufferedReader bfr = new BufferedReader(adapter);

在这个示例中,客户需要使用BufferedReader来读取文件字符流。然而,现有的接口只能提供字节流,例如FileInputStream。为了满足客户的需求,我们需要对现有的接口进行适配。

InputStreamReader充当了适配器的角色。它持有一个FileInputStream对象,并通过适配将其转换为所需的字符流接口。可以将InputStreamReader视为适配器模式的具体实现之一。

通过使用适配器模式,我们成功地将字节流接口适配成了字符流接口,使得BufferedReader能够以字符方式读取文件内容,从而满足了客户的需求。

适配器模式有两种比较常见的实现方式:

  • 类适配器模式(使用继承)
  • 对象适配器模式(使用组合)

类适配器实现

类适配器通过继承来实现适配器功能

java 复制代码
// 目标接口
public interface Target {
    void request();
}

// 被适配者
public class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee: specificRequest");
    }
}

// 适配器
public class Adapter extends Adaptee implements Target {
    /**
     * 采用继承的方式实现转换功能
     */
    @Override
    public void request() {
        super.specificRequest();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request(); // 通过适配器调用被适配者方法
    }
}

对象适配器实现

对象适配器通过组合来实现适配器功能

以下是一个简单的示例代码:

java 复制代码
// 目标接口
public interface Target {
    void request();
}

// 被适配者
public class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee: specificRequest");
    }
}

// 适配器
public class Adapter implements Target {
    private Adaptee adaptee;

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

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request(); // 通过适配器调用被适配者方法
    }
}

对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。

一般而言,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,可以适配不同的被适配类,并且允许动态替换被适配对象。另外,对象适配器不受被适配类的限制。

类适配器通过继承现有接口类并实现目标接口,这样的话会使得现有接口类完全对适配器暴露,使得适配器具有现有接口类的全部功能,破坏了封装性,会引入一些设计上的限制。此外从逻辑上来说,这也是不符合常理的,适配器要做的是扩展现有接口类的功能而不是替代,类适配器只有在特定条件下会被使用。

对象适配器持有现有接口类一个实例,并扩展其功能,实现目标接口。这是推荐的方式,优先采用组合而不是继承,会使得代码更利于维护。

优缺点

优点:

  • 透明性:适配器模式可以使客户端对目标类和适配者类的使用变得透明。客户端只需要与目标接口进行交互,无需了解适配者类的内部实现细节。
  • 重用性:通过适配器模式,可以复用已经存在的可复用类。适配器将这些类适配到目标接口中,使得它们可以在新的环境下被重用。
  • 灵活性:适配器模式可以动态地适配不同的适配者类,从而满足不同的客户端需求。适配器模式允许在运行时更改适配器,以适应不同的情况和要求。

缺点:

  • 过多的适配器类:如果系统中存在大量的适配器类,会让系统非常零乱,不易整体进行把握,可能会导致代码结构的复杂性增加。
  • 可能引入额外的复杂性:适配器模式可能会导致系统中增加额外的类和对象,从而增加系统的复杂性。

总结

适配器模式通过将不兼容的接口转换为可协同工作的形式,实现了不同类之间的互操作。它可以提高代码的复用性和灵活性。但在使用过程中需要注意选择合适的适配器类型,并确保适配器能够正确地转换接口。

相关推荐
大名顶顶5 分钟前
【JAVA实战】如何使用 Apache POI 在 Java 中写入 Excel 文件
java·spring boot·后端·计算机·程序员·编程·软件开发
stevewongbuaa1 小时前
一些烦人的go设置 goland
开发语言·后端·golang
花心蝴蝶.5 小时前
Spring MVC 综合案例
java·后端·spring
落霞的思绪5 小时前
Redis实战(黑马点评)——关于缓存(缓存更新策略、缓存穿透、缓存雪崩、缓存击穿、Redis工具)
数据库·spring boot·redis·后端·缓存
m0_748255655 小时前
环境安装与配置:全面了解 Go 语言的安装与设置
开发语言·后端·golang
SomeB1oody10 小时前
【Rust自学】14.6. 安装二进制crate
开发语言·后端·rust
患得患失94912 小时前
【Django DRF Apps】【文件上传】【断点上传】从零搭建一个普通文件上传,断点续传的App应用
数据库·后端·django·sqlite·大文件上传·断点上传
customer0813 小时前
【开源免费】基于SpringBoot+Vue.JS校园失物招领系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
中國移动丶移不动13 小时前
Java 反射与动态代理:实践中的应用与陷阱
java·spring boot·后端·spring·mybatis·hibernate
uzong15 小时前
Mybatis-plus 更新 Null 的策略踩坑记
java·后端