name: 适配器模式 description: "将一个类的接口转换为客户端期望的另一个接口,解决不兼容问题。" license: MIT
适配器模式 (Adapter Pattern)
核心概念
Adapter是一种结构型设计模式,用于将一个不兼容的类的接口转换为客户端期望的接口。适配器充当"翻译"角色,使得原本无法协同工作的对象可以一起工作。
核心原则:
- 解决接口不兼容问题
- 无需修改原有接口即可集成新对象
- 促进代码复用,延长类的生命周期
- 支持第三方库的集成
适配方式:
- 类适配 (Class Adapter) - 通过继承实现
- 对象适配 (Object Adapter) - 通过组合实现 ⭐ 推荐
何时使用
始终使用:
- 需要使用第三方库但接口不兼容
- 旧系统与新系统集成
- 多个子系统接口不统一
- 希望不修改原有代码的情况下扩展功能
触发短语:
- "这个库的API不适配我们的系统"
- "需要集成遗留系统,但接口完全不同"
- "期望一个统一的接口来操作不同的实现"
典型场景:
| 场景 | 需适配的 | 目标接口 | 适配器 |
|---|---|---|---|
| 支付网关整合 | Alipay, WeChat SDK | PaymentGateway | AlipayAdapter |
| 日期处理 | java.util.Date, LocalDateTime | DateConverter | DateAdapter |
| 数据库驱动 | MySQL, PostgreSQL | JdbcConnection | DbAdapter |
| UI组件库 | 第三方组件 | 内部UI接口 | ComponentAdapter |
4个实现方法
方法1: 对象适配器 (Object Adapter) ⭐推荐
通过组合原对象,适配其接口到目标接口。
// 不兼容的现有接口 (第三方库)
public class LegacyPaymentSystem {
public String processPayment(double amount) {
return "支付宝处理: " + amount;
}
}
// 目标接口 (系统期望)
public interface PaymentGateway {
boolean pay(double amount);
String getStatus();
}
// 对象适配器 - 通过组合
public class PaymentAdapter implements PaymentGateway {
private LegacyPaymentSystem legacySystem;
public PaymentAdapter(LegacyPaymentSystem system) {
this.legacySystem = system;
}
@Override
public boolean pay(double amount) {
try {
String result = legacySystem.processPayment(amount);
System.out.println("适配结果: " + result);
return result.contains("成功");
} catch (Exception e) {
return false;
}
}
@Override
public String getStatus() {
return "已支付";
}
}
// 使用
LegacyPaymentSystem legacy = new LegacyPaymentSystem();
PaymentGateway adapter = new PaymentAdapter(legacy);
adapter.pay(100.0);
优点: 灵活,不修改原类,可适配多个接口 缺点: 需要包装对象
方法2: 类适配器 (Class Adapter)
通过继承原类来适配。
// 类适配器 - 通过继承
public class DirectPaymentAdapter extends LegacyPaymentSystem
implements PaymentGateway {
@Override
public boolean pay(double amount) {
String result = super.processPayment(amount);
return result.contains("成功");
}
@Override
public String getStatus() {
return "已处理";
}
}
// 使用
PaymentGateway adapter = new DirectPaymentAdapter();
adapter.pay(100.0);
优点: 简单直接 缺点: 受限于Java单继承,不够灵活
方法3: 双向适配器 (Two-Way Adapter)
同时适配两个不兼容的接口。
// 两个不兼容的接口
public interface ChinesePayment {
String payWithUnifiedOrder(double amount);
}
public interface WeternPayment {
boolean processPayment(double amount);
}
// 双向适配器
public class BidirectionalAdapter implements ChinesePayment, WeternPayment {
private Object target;
public BidirectionalAdapter(Object target) {
this.target = target;
}
@Override
public String payWithUnifiedOrder(double amount) {
// 适配到 WeternPayment 接口
if (target instanceof WeternPayment) {
boolean success = ((WeternPayment) target).processPayment(amount);
return success ? "成功" : "失败";
}
return "不支持";
}
@Override
public boolean processPayment(double amount) {
// 适配到 ChinesePayment 接口
if (target instanceof ChinesePayment) {
String result = ((ChinesePayment) target).payWithUnifiedOrder(amount);
return result.contains("成功");
}
return false;
}
}
方法4: 装饰改进的适配器
在适配的同时添加额外功能。
public class EnhancedPaymentAdapter implements PaymentGateway {
private LegacyPaymentSystem legacy;
private List<PaymentInterceptor> interceptors = new ArrayList<>();
public EnhancedPaymentAdapter(LegacyPaymentSystem legacy) {
this.legacy = legacy;
}
public void addInterceptor(PaymentInterceptor interceptor) {
interceptors.add(interceptor);
}
@Override
public boolean pay(double amount) {
// 前拦截器
for (PaymentInterceptor interceptor : interceptors) {
if (!interceptor.beforePay(amount)) {
return false;
}
}
// 适配的支付
boolean result = legacyProcessPayment(amount);
// 后拦截器
for (PaymentInterceptor interceptor : interceptors) {
interceptor.afterPay(amount, result);
}
return result;
}
private boolean legacyProcessPayment(double amount) {
try {
String response = legacy.processPayment(amount);
return response.contains("成功");
} catch (Exception e) {
return false;
}
}
@Override
public String getStatus() { return "已处理"; }
}
public interface PaymentInterceptor {
boolean beforePay(double amount);
void afterPay(double amount, boolean success);
}
// 使用
EnhancedPaymentAdapter adapter = new EnhancedPaymentAdapter(legacy);
adapter.addInterceptor(new LoggingInterceptor());
adapter.addInterceptor(new ValidationInterceptor());
adapter.pay(100.0);
常见问题与解决方案
❌ 问题1: 适配器性能开销
症状: 频繁调用适配器,性能下降。
根本原因: 每次调用都经过一层包装,特别是双适配。
解决方案:
// ✅ 缓存适配后的对象
public class CachedPaymentAdapter implements PaymentGateway {
private Map<String, Object> cache = new ConcurrentHashMap<>();
private LegacyPaymentSystem legacy;
@Override
public boolean pay(double amount) {
String key = "payment_" + amount;
Object cached = cache.get(key);
if (cached != null) {
return (Boolean) cached;
}
boolean result = legacyProcessPayment(amount);
cache.put(key, result);
return result;
}
private boolean legacyProcessPayment(double amount) {
return legacy.processPayment(amount).contains("成功");
}
@Override
public String getStatus() { return "已处理"; }
}
❌ 问题2: 接口不完全兼容
症状: 适配器无法完整适配所有功能。
根本原因: 被适配类功能集合与目标接口功能集合不匹配。
解决方案:
// ✅ 分离适配与补充功能
public interface FullPaymentGateway extends PaymentGateway {
boolean refund(String transactionId);
List<Transaction> getHistory();
}
public class CompletePaymentAdapter implements FullPaymentGateway {
private LegacyPaymentSystem legacy;
private List<Transaction> localHistory = new ArrayList<>();
@Override
public boolean pay(double amount) {
boolean result = legacy.processPayment(amount).contains("成功");
if (result) {
localHistory.add(new Transaction(amount, System.currentTimeMillis()));
}
return result;
}
@Override
public boolean refund(String transactionId) {
// 补充功能: 旧系统不支持退款
localHistory.removeIf(t -> t.getId().equals(transactionId));
return true;
}
@Override
public List<Transaction> getHistory() {
return new ArrayList<>(localHistory);
}
@Override
public String getStatus() { return "已处理"; }
}
❌ 问题3: 第三方库版本变更导致适配器失效
症状: 升级第三方库后,适配器报错。
根本原因: 适配器强耦合于特定版本的第三方库。
解决方案:
// ✅ 使用策略模式支持多版本
public interface PaymentAdapterStrategy {
boolean pay(double amount);
}
public class AlipayV1Adapter implements PaymentAdapterStrategy {
private LegacyPaymentSystem legacyV1;
@Override
public boolean pay(double amount) {
return legacyV1.processPayment(amount).contains("成功");
}
}
public class AlipayV2Adapter implements PaymentAdapterStrategy {
private NewPaymentSystem newV2;
@Override
public boolean pay(double amount) {
return newV2.executePayment(amount) == PaymentResult.SUCCESS;
}
}
public class VersionAwareAdapter implements PaymentGateway {
private PaymentAdapterStrategy strategy;
public VersionAwareAdapter(String version) {
if ("1.0".equals(version)) {
this.strategy = new AlipayV1Adapter(...);
} else {
this.strategy = new AlipayV2Adapter(...);
}
}
@Override
public boolean pay(double amount) {
return strategy.pay(amount);
}
@Override
public String getStatus() { return "已处理"; }
}
❌ 问题4: 多个不兼容接口混合导致混乱
症状: 系统中混用不同的支付接口,代码难以维护。
根本原因: 缺陷统一的适配策略。
解决方案:
// ✅ 使用层次适配器
public abstract class BasePaymentAdapter implements PaymentGateway {
protected abstract void executePayment(double amount);
protected abstract String extractStatus();
@Override
public final boolean pay(double amount) {
try {
executePayment(amount);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public final String getStatus() {
return extractStatus();
}
}
public class SpecificAlipayAdapter extends BasePaymentAdapter {
private LegacyPaymentSystem system;
@Override
protected void executePayment(double amount) {
system.processPayment(amount);
}
@Override
protected String extractStatus() {
return "已支付";
}
}
类适配 vs 对象适配对比
| 方面 | 类适配 | 对象适配 |
|---|---|---|
| 实现方式 | 继承 | 组合 |
| 灵活性 | 低 (单一父类) | 高 |
| 多适配 | 不支持 | 支持 |
| 性能 | 略好 | 略差 |
| 推荐度 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
最佳实践
✅ 优先对象适配 - 灵活性更好
✅ 隔离第三方库 - 通过适配器屏蔽变化
✅ 单一职责 - 适配器只负责接口转换
✅ 缓存策略 - 高频调用时缓存适配结果
✅ 版本管理 - 支持多版本第三方库
✅ 异常处理 - 完整的错误处理和日志
何时避免
❌ 简单的接口转换可以直接修改源类
❌ 不兼容问题源于设计缺陷,应该重构而非适配
❌ 过度适配导致代码复杂度增加
真实案例
案例1: 支付网关整合
不同支付商 (支付宝、微信、Stripe) 接口完全不同,使用适配器统一为内部接口。
案例2: 日期处理库
java.util.Date 与 java.time.LocalDateTime 接口不兼容,适配器转换。
案例3: 旧系统集成
集成20年前的遗留系统,现代系统与之通信需要适配器转换。