文章目录
- 前言
- 一、概念
- 二、核心思想
- 三、Java代码实现
-
- [1. 定义目标接口(系统期望的支付接口)](#1. 定义目标接口(系统期望的支付接口))
- [2. 定义适配者(第三方支付类,接口不兼容)](#2. 定义适配者(第三方支付类,接口不兼容))
- [3. 定义类适配器(继承适配者,实现目标接口)](#3. 定义类适配器(继承适配者,实现目标接口))
- [4. 定义对象适配器(推荐,组合适配者,实现目标接口)](#4. 定义对象适配器(推荐,组合适配者,实现目标接口))
- [5. 客户端使用代码](#5. 客户端使用代码)
- [6. 扩展:新增银联支付适配(符合开闭原则)](#6. 扩展:新增银联支付适配(符合开闭原则))
- 四、优缺点
-
- [1. 优点](#1. 优点)
- [2. 缺点](#2. 缺点)
- 五、应用场景
- 六、注意事项
- 总结
前言
在AI时代,代码的编写可以被大模型辅助甚至替代,但程序员真正的核心竞争力是技术思维------设计模式这类沉淀了数十年的"内功心法",决定了代码的可维护性、扩展性和稳定性,是AI无法完全替代的核心能力。适配器模式作为结构型模式的核心成员,专注于"兼容不同接口、复用现有代码",解决了系统中"接口不兼容但功能可用"的问题,是系统集成、老旧代码复用的最优范式。
一、概念
适配器模式(Adapter Pattern)是一种结构型设计模式,核心目标是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。简单来说,适配器就像生活中的"电源转换器"------比如欧洲的插头是圆孔,中国的插座是扁孔,转换器可以让欧洲插头适配中国插座,而无需修改插头或插座本身。
在编程中,当我们需要使用一个已有类(如第三方库、老旧系统代码),但它的接口不符合当前系统的要求时,就可以用适配器模式封装这个类,对外提供符合系统要求的接口,既复用了现有代码,又避免了修改原有类(符合开闭原则)。
二、核心思想
- 目标接口(Target):客户端期望的、符合系统规范的接口,是适配器对外暴露的接口;
- 适配者(Adaptee):已有但接口不兼容的类/对象,是需要被适配的"原有组件";
- 适配器(Adapter):实现目标接口,同时持有适配者的引用,将客户端对目标接口的调用,转换为对适配者的调用,完成接口转换;
- 客户端(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. 优点
- 接口兼容复用:无需修改原有适配者代码,即可让接口不兼容的类复用,保护原有代码(符合开闭原则);
- 解耦客户端与适配者:客户端仅依赖目标接口,与适配者解耦,降低系统耦合度;
- 灵活性高:对象适配器通过组合方式,可适配多个适配者(如一个适配器适配多个第三方类),类适配器则受限于单继承;
- 简化系统集成:在集成第三方库、老旧系统时,无需重构原有代码,只需添加适配器即可兼容。
2. 缺点
- 增加系统复杂度:引入适配器后,系统中新增了适配器类,增加了代码量和理解成本;
- 类适配器局限性:Java单继承特性导致类适配器只能适配一个适配者,灵活性低,实际开发中较少使用;
- 适配复杂接口时成本高:若适配者接口复杂(包含大量方法),适配器需实现所有方法,代码冗余。
五、应用场景
适配器模式适用于接口不兼容、需复用现有代码、系统集成的场景:
- 第三方库集成:使用第三方框架/库时,其接口与系统接口不一致,如支付SDK、日志框架、数据库驱动;
- 老旧系统改造:维护老旧系统时,原有代码接口不符合新需求,需复用原有功能但不想修改代码;
- 跨平台适配:如不同操作系统的API适配(Windows/Linux的文件操作API)、不同数据库的JDBC适配;
- 接口标准化:将多个不同接口的组件,适配为统一的标准接口,便于客户端统一调用(如各种支付方式适配为统一的Payment接口);
- 框架中的应用 :Java中的
InputStreamReader(将字节流InputStream适配为字符流Reader)、OutputStreamWriter都是适配器模式的经典实现。
六、注意事项
- 区分适配器模式与装饰者模式:适配器模式关注"接口转换",装饰者模式关注"功能增强";适配器改变接口,装饰者不改变接口仅增强功能;
- 优先使用对象适配器:对象适配器基于组合,灵活性更高,可适配多个适配者,避免类适配器的单继承限制;
- 避免过度适配:若接口差异小,直接修改原有类的接口更简洁,无需引入适配器;
- 适配器的单一职责:一个适配器只负责适配一个(或一组相关)适配者,避免一个适配器适配多个不相关的类导致逻辑混乱。
总结
- 适配器模式核心是接口转换、兼容复用,通过适配器将不兼容的接口转换为客户端期望的接口,实现现有代码的复用;
- 实际开发中优先使用对象适配器(组合方式),避免类适配器的单继承局限性;
- 优势是解耦、复用、灵活,缺点是增加复杂度,适用于第三方库集成、老旧系统改造、接口标准化等场景;
- Java中的
InputStreamReader/OutputStreamWriter是适配器模式的经典应用,理解其实现逻辑可快速上手实际开发。