【设计模式】结构型-适配器模式

文章目录

  • 前言
  • 一、概念
  • 二、核心思想
  • 三、Java代码实现
    • [1. 定义目标接口(系统期望的支付接口)](#1. 定义目标接口(系统期望的支付接口))
    • [2. 定义适配者(第三方支付类,接口不兼容)](#2. 定义适配者(第三方支付类,接口不兼容))
    • [3. 定义类适配器(继承适配者,实现目标接口)](#3. 定义类适配器(继承适配者,实现目标接口))
    • [4. 定义对象适配器(推荐,组合适配者,实现目标接口)](#4. 定义对象适配器(推荐,组合适配者,实现目标接口))
    • [5. 客户端使用代码](#5. 客户端使用代码)
    • [6. 扩展:新增银联支付适配(符合开闭原则)](#6. 扩展:新增银联支付适配(符合开闭原则))
  • 四、优缺点
    • [1. 优点](#1. 优点)
    • [2. 缺点](#2. 缺点)
  • 五、应用场景
  • 六、注意事项
  • 总结

前言

在AI时代,代码的编写可以被大模型辅助甚至替代,但程序员真正的核心竞争力是技术思维------设计模式这类沉淀了数十年的"内功心法",决定了代码的可维护性、扩展性和稳定性,是AI无法完全替代的核心能力。适配器模式作为结构型模式的核心成员,专注于"兼容不同接口、复用现有代码",解决了系统中"接口不兼容但功能可用"的问题,是系统集成、老旧代码复用的最优范式。

一、概念

适配器模式(Adapter Pattern)是一种结构型设计模式,核心目标是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。简单来说,适配器就像生活中的"电源转换器"------比如欧洲的插头是圆孔,中国的插座是扁孔,转换器可以让欧洲插头适配中国插座,而无需修改插头或插座本身。

在编程中,当我们需要使用一个已有类(如第三方库、老旧系统代码),但它的接口不符合当前系统的要求时,就可以用适配器模式封装这个类,对外提供符合系统要求的接口,既复用了现有代码,又避免了修改原有类(符合开闭原则)。

二、核心思想

  1. 目标接口(Target):客户端期望的、符合系统规范的接口,是适配器对外暴露的接口;
  2. 适配者(Adaptee):已有但接口不兼容的类/对象,是需要被适配的"原有组件";
  3. 适配器(Adapter):实现目标接口,同时持有适配者的引用,将客户端对目标接口的调用,转换为对适配者的调用,完成接口转换;
  4. 客户端(Client):仅依赖目标接口,无需知道适配者的存在,通过适配器间接使用适配者的功能。

适配器模式的核心本质是接口转换、兼容复用 ------不修改原有适配者的代码,通过适配器封装适配者,对外提供符合要求的接口,实现"旧接口复用、新系统兼容",是系统集成和代码复用的关键模式。

三、Java代码实现

以"支付系统集成"场景为例:现有系统期望的支付接口是Payment(包含pay(double amount)方法),但第三方支付库提供的微信支付类WeChatPay的接口是weChatPay(double money),支付宝支付类Alipay的接口是aliPay(double total),接口不兼容。用适配器模式封装这两个第三方类,使其适配系统的目标接口。

1. 定义目标接口(系统期望的支付接口)

java 复制代码
/**
 * 目标接口:系统期望的支付接口
 * 客户端仅依赖此接口,无需关心具体支付方式的实现
 */
public interface Payment {
    // 统一的支付方法:传入支付金额,返回支付结果
    String pay(double amount);
}

2. 定义适配者(第三方支付类,接口不兼容)

java 复制代码
/**
 * 适配者1:微信支付(第三方类,接口不符合系统要求)
 */
public class WeChatPay {
    // 微信支付特有方法,参数名、返回格式与目标接口不一致
    public String weChatPay(double money) {
        return "微信支付成功,金额:" + money + "元";
    }
}

/**
 * 适配者2:支付宝支付(第三方类,接口不符合系统要求)
 */
public class Alipay {
    // 支付宝支付特有方法,参数名、返回格式与目标接口不一致
    public String aliPay(double total) {
        return "支付宝支付成功,金额:" + total + "元";
    }
}

3. 定义类适配器(继承适配者,实现目标接口)

java 复制代码
/**
 * 类适配器:微信支付适配器(继承适配者+实现目标接口)
 * 适用场景:适配者是类且无继承限制(Java单继承,局限性大)
 */
public class WeChatPayClassAdapter extends WeChatPay implements Payment {
    @Override
    public String pay(double amount) {
        // 将目标接口的调用,转换为对适配者的调用(接口转换核心)
        return super.weChatPay(amount);
    }
}

4. 定义对象适配器(推荐,组合适配者,实现目标接口)

java 复制代码
/**
 * 对象适配器:支付宝支付适配器(持有适配者引用+实现目标接口)
 * 适用场景:适配者是类/接口、多继承场景,灵活性更高(推荐)
 */
public class AlipayObjectAdapter implements Payment {
    // 持有适配者引用(组合方式,而非继承)
    private Alipay alipay;

    // 构造方法注入适配者(灵活切换适配者实例)
    public AlipayObjectAdapter(Alipay alipay) {
        this.alipay = alipay;
    }

    @Override
    public String pay(double amount) {
        // 将目标接口的调用,转换为对适配者的调用
        return alipay.aliPay(amount);
    }
}

/**
 * 扩展:微信支付的对象适配器(更通用的实现方式)
 */
public class WeChatPayObjectAdapter implements Payment {
    private WeChatPay weChatPay;

    public WeChatPayObjectAdapter(WeChatPay weChatPay) {
        this.weChatPay = weChatPay;
    }

    @Override
    public String pay(double amount) {
        return weChatPay.weChatPay(amount);
    }
}

5. 客户端使用代码

java 复制代码
/**
 * 客户端:支付业务层
 * 仅依赖目标接口Payment,无需知道适配者和适配器的细节
 */
public class Client {
    public static void main(String[] args) {
        // 1. 使用类适配器(微信支付)
        Payment weChatPayment = new WeChatPayClassAdapter();
        System.out.println(weChatPayment.pay(100.5));

        // 2. 使用对象适配器(支付宝支付)
        Alipay alipay = new Alipay();
        Payment aliPayment = new AlipayObjectAdapter(alipay);
        System.out.println(aliPayment.pay(200.8));

        // 3. 使用对象适配器(微信支付,更通用)
        WeChatPay weChatPay = new WeChatPay();
        Payment weChatPayment2 = new WeChatPayObjectAdapter(weChatPay);
        System.out.println(weChatPayment2.pay(50.0));
    }
}

输出结果:

复制代码
微信支付成功,金额:100.5元
支付宝支付成功,金额:200.8元
微信支付成功,金额:50.0元

6. 扩展:新增银联支付适配(符合开闭原则)

java 复制代码
// 1. 新增适配者:银联支付(第三方类)
public class UnionPay {
    public String unionPay(double sum) {
        return "银联支付成功,金额:" + sum + "元";
    }
}

// 2. 新增适配器:银联支付对象适配器(无需修改原有代码)
public class UnionPayObjectAdapter implements Payment {
    private UnionPay unionPay;

    public UnionPayObjectAdapter(UnionPay unionPay) {
        this.unionPay = unionPay;
    }

    @Override
    public String pay(double amount) {
        return unionPay.unionPay(amount);
    }
}

// 3. 客户端使用(直接新增调用,无需修改原有业务逻辑)
public class Client {
    public static void main(String[] args) {
        UnionPay unionPay = new UnionPay();
        Payment unionPayment = new UnionPayObjectAdapter(unionPay);
        System.out.println(unionPayment.pay(300.2));
    }
}

四、优缺点

1. 优点

  1. 接口兼容复用:无需修改原有适配者代码,即可让接口不兼容的类复用,保护原有代码(符合开闭原则);
  2. 解耦客户端与适配者:客户端仅依赖目标接口,与适配者解耦,降低系统耦合度;
  3. 灵活性高:对象适配器通过组合方式,可适配多个适配者(如一个适配器适配多个第三方类),类适配器则受限于单继承;
  4. 简化系统集成:在集成第三方库、老旧系统时,无需重构原有代码,只需添加适配器即可兼容。

2. 缺点

  1. 增加系统复杂度:引入适配器后,系统中新增了适配器类,增加了代码量和理解成本;
  2. 类适配器局限性:Java单继承特性导致类适配器只能适配一个适配者,灵活性低,实际开发中较少使用;
  3. 适配复杂接口时成本高:若适配者接口复杂(包含大量方法),适配器需实现所有方法,代码冗余。

五、应用场景

适配器模式适用于接口不兼容、需复用现有代码、系统集成的场景:

  1. 第三方库集成:使用第三方框架/库时,其接口与系统接口不一致,如支付SDK、日志框架、数据库驱动;
  2. 老旧系统改造:维护老旧系统时,原有代码接口不符合新需求,需复用原有功能但不想修改代码;
  3. 跨平台适配:如不同操作系统的API适配(Windows/Linux的文件操作API)、不同数据库的JDBC适配;
  4. 接口标准化:将多个不同接口的组件,适配为统一的标准接口,便于客户端统一调用(如各种支付方式适配为统一的Payment接口);
  5. 框架中的应用 :Java中的InputStreamReader(将字节流InputStream适配为字符流Reader)、OutputStreamWriter都是适配器模式的经典实现。

六、注意事项

  1. 区分适配器模式与装饰者模式:适配器模式关注"接口转换",装饰者模式关注"功能增强";适配器改变接口,装饰者不改变接口仅增强功能;
  2. 优先使用对象适配器:对象适配器基于组合,灵活性更高,可适配多个适配者,避免类适配器的单继承限制;
  3. 避免过度适配:若接口差异小,直接修改原有类的接口更简洁,无需引入适配器;
  4. 适配器的单一职责:一个适配器只负责适配一个(或一组相关)适配者,避免一个适配器适配多个不相关的类导致逻辑混乱。

总结

  1. 适配器模式核心是接口转换、兼容复用,通过适配器将不兼容的接口转换为客户端期望的接口,实现现有代码的复用;
  2. 实际开发中优先使用对象适配器(组合方式),避免类适配器的单继承局限性;
  3. 优势是解耦、复用、灵活,缺点是增加复杂度,适用于第三方库集成、老旧系统改造、接口标准化等场景;
  4. Java中的InputStreamReader/OutputStreamWriter是适配器模式的经典应用,理解其实现逻辑可快速上手实际开发。
相关推荐
Yu_Lijing3 小时前
基于C++的《Head First设计模式》笔记——蝇量模式
c++·笔记·设计模式
敲代码的约德尔人19 小时前
JavaScript 设计模式完全指南
javascript·设计模式
han_1 天前
JavaScript设计模式(二):策略模式实现与应用
前端·javascript·设计模式
庞轩px2 天前
HotSpot详解——符号引用、句柄池、直接指针的终极解密
java·jvm·设计模式·内存·虚拟机·引用·klass
Yu_Lijing2 天前
基于C++的《Head First设计模式》笔记——责任链模式
c++·笔记·设计模式·责任链模式
青木川崎2 天前
设计模式之面试题
java·开发语言·设计模式
Yu_Lijing3 天前
基于C++的《Head First设计模式》笔记——生成器模式
c++·笔记·设计模式
sg_knight3 天前
设计模式实战:策略模式(Strategy)
java·开发语言·python·设计模式·重构·架构·策略模式