适配器模式

适合阅读本专栏的人群包括:

  • 想提升代码质量和架构思维的 Java 开发者
  • 在工作中面对复杂业务、代码难以维护的工程师
  • 想准备面试、系统复习设计模式知识的同学

阅读完本专栏,你将掌握:

  • 23 种设计模式的结构、适用场景和最佳实践
  • 面向对象六大设计原则的使用方式
  • 如何用设计模式解决常见业务场景问题
  • 如何重构低质量代码,提升扩展性与可维护性

任何问题都可以在留言区指出,作者看到后会第一时间回复。
概念总是生僻的,可以结合代码多体会多练习。
如果本文章给你带来一点点收获请点点赞支持一下,谢谢各位架构师,技术专家,专业大拿。
其他模式详解:设计模式入门

适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。它主要用于使现有的类与其他类的接口兼容,而无需修改其源代码。

适用场景:

  • 接口不兼容但功能可用
    当一个类的功能满足需求,但其接口与客户端期望的不一致时,使用适配器进行“翻译”。
  • 集成第三方库或 SDK
    第三方组件的 API 与当前系统规范不同,通过适配器将其封装为统一接口,便于调用和管理。
  • 复用遗留系统(Legacy Code)
    老系统模块仍在运行,但接口陈旧,通过适配器让新系统能无缝调用旧代码,避免重写。
  • 统一多种数据格式或服务接口
    不同系统输出的数据(如 JSON、XML)或服务接口不同,使用适配器转换为统一格式处理。
  • 保持向后兼容性
    系统升级后接口变更,为支持老客户端调用,提供适配器将旧接口映射到新实现。
  • 跨平台或跨环境组件整合
    如 GUI 组件、数据库驱动等在不同平台有不同接口,通过适配器对外提供一致调用方式。

适配器模式通常分为两种类型

  1. 类适配器:使用继承的方式实现适配器功能。
  2. 对象适配器(推荐):使用组合的方式实现适配器功能。

结构

适配器模式包含以下几个主要角色:

  • 目标接口(Target):定义客户需要的接口。
  • 适配者类(Adaptee):定义一个已经存在的接口,这个接口需要适配。
  • 适配器类(Adapter):实现目标接口,并通过组合或继承的方式调用适配者类中的方法,从而实现目标接口。

在这里插入图片描述

适配器模式的优点

  1. 单一职责原则:通过适配器模式可以将不同接口的实现代码分开,从而使得每个类的职责更加单一。
  2. 开闭原则:适配器模式使得旧的类可以在不修改代码的情况下与新的接口兼容。

适配器模式的缺点

  1. 增加代码复杂度:适配器模式在引入新的适配器类的同时,也增加了代码的复杂度。
  2. 性能开销:在某些情况下,适配器模式可能会引入一些额外的性能开销,尤其是当适配器进行大量的对象包装和解包操作时。

总之,适配器模式是一种非常有用的设计模式,它能够让原本不兼容的接口一起工作,从而提高代码的复用性和可扩展性。

1.类适配器

类适配器通过多重继承来实现适配器功能。Java 不支持多重继承,因此在 Java 中,类适配器通过实现一个接口并继承一个类来实现适配器功能。

假设我们有一个旧的接口 OldInterface,和一个新的接口 NewInterface,我们想使 OldClass 适配 NewInterface

// 旧接口
interface OldInterface {
    void oldMethod();
}

// 新接口
interface NewInterface {
    void newMethod(String methodType);
}

// 旧类
class OldClass implements OldInterface {
    public void oldMethod() {
        System.out.println("Old method");
    }
}

// 类适配器
class ClassAdapter extends OldClass implements NewInterface {
    @Override
    public void newMethod(String methodType) {
        if("old".equls(methodType)){
        	oldMethod(); // 适配旧方法
        }else {
            System.out.println("New method");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        NewInterface adapter = new ClassAdapter();
        adapter.newMethod("old"); // 输出 "Old method"
    }
}

2.对象适配器

对象适配器通过组合的方式实现适配器功能。适配器持有被适配对象的实例,并通过调用其方法来实现适配功能。

// 旧接口
interface OldInterface {
    void oldMethod();
}

// 新接口
interface NewInterface {
    void newMethod(String methodType);
}

// 旧类
class OldClass implements OldInterface {
    public void oldMethod() {
        System.out.println("Old method");
    }
}

// 对象适配器
class ObjectAdapter implements NewInterface {
    private OldClass oldClass;

    public ObjectAdapter(OldClass oldClass) {
        this.oldClass = oldClass;
    }

    @Override
    public void newMethod(String methodType) {
        if("old".equls(methodType)){
        	oldMethod(); // 适配旧方法
        }else {
            System.out.println("New method");
        }
    }

}

public class Main {
    public static void main(String[] args) {
        OldClass oldClass = new OldClass();
        NewInterface adapter = new ObjectAdapter(oldClass);
        adapter.newMethod("old"); // 输出 "Old method"
    }
}

适配器模式的重点 是 adapter 类中的适配方法,适配方法(newMethod) 中的逻辑可以自由定义来适应需求,上文所举例子需要调用方指定调用 new 方法 还是 old 方法。再举一个列子,之前的类(源对象)可以读取 mp3 格式文件,新的类中提供了读取 mp4 文件的方法。我们的需求是新方法也要兼容读取 mp3. 这时候我们就可以使用适配器模式进行适配。

// 对象适配器
class MediaAdapter implements NewInterface {
    private Mp3Class mp3Class = new Mp3Class();

    @Override
    public void newMethod(File mediaFile) {
        String type = mediaFile.getFileExtension(); // 此处为伪代码
        if("mp3".equls(type)){
        	mp3Class.read(mediaFile);
        }else if("mp4".equls(type)) {
            readMp4(mediaFile)} else {
            System.out.println("不兼容的格式");
        }
    }
    
    public void readMp4(File mediaFile){
        System.out.println("read mp4");
    }

}

适配器模式在使用时保证服务端对外只提供新接口,但是客户端可以通过参数指定来调用 老方法,或者由服务端自动决定调用哪个方法(比如 mp4 这个例子)。大家思考一下,ESB 系统是否可以称作一个巨大的适配器?欢迎在品论区留言。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐