系列导读:完成创建型模式后,我们进入结构型模式的学习。适配器模式是结构型模式的开篇,解决接口不兼容的问题。
解决什么问题:将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。用于系统集成和第三方库对接。
在软件开发中,我们经常需要使用第三方库或者对接外部系统,但它们的接口往往与我们的系统不兼容。比如,老系统使用XML格式数据,新系统使用JSON格式;或者需要集成的支付接口与现有的支付抽象不匹配。
适配器模式就像现实中的转换插头一样,让不匹配的接口能够正常工作。它在不修改原有代码的前提下,通过一个适配器类来桥接两个不兼容的接口。
本文在系列中的位置:
- 前置知识:创建型模式:原型模式
- 系列角色:结构型模式入门
- 难度等级:★★☆☆☆(概念简单,实用性强)
- 后续学习:桥接模式
目录
1. 模式概述
适配器模式是一种结构型设计模式,它允许将不兼容的接口转换为客户端期望的接口。适配器模式通过创建一个中间层来解决接口不兼容的问题,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
1.1 定义
适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。通过引入适配器,系统可以复用已有的功能模块,提升系统的灵活性和可扩展性。
1.2 目的
- 实现接口转换,兼容不同系统或模块
- 提高类的复用性,减少重复开发
- 降低系统耦合度,提升维护性
2. 使用场景
适配器模式适用于以下场景:
接口不兼容
- 新旧系统集成:如老系统接口与新系统不兼容,需要适配。
- 第三方库使用:引入外部库时接口不一致。
- 遗留系统改造:升级或重构时需要兼容旧接口。
类复用
- 复用现有类:已有类功能满足需求但接口不同。
- 避免代码重复:通过适配器复用已有实现。
- 保持接口一致性:对外暴露统一接口。
系统解耦
- 降低耦合度:客户端与具体实现解耦。
- 提高灵活性:可灵活切换不同实现。
- 便于维护:适配器作为中间层,便于后续扩展。
多环境适配
- 跨平台开发:如移动端与PC端接口差异。
- 多版本支持:兼容不同版本的接口。
- 环境迁移:如本地与云端接口差异。
真实业务背景举例:
- 某大型企业在系统升级时,需将老系统的SOAP接口适配为新系统的RESTful接口,避免大规模重构。
- 金融行业接入多家第三方支付平台,通过适配器统一支付接口,简化业务开发。
3. 优缺点分析
3.1 优点
- 接口转换:解决接口不兼容问题,提升系统复用性。保持对外接口一致,便于系统集成。客户端无需修改即可适配新实现。
- 灵活性:支持动态适配,便于扩展和维护。可通过组合或继承灵活实现适配。适配器可复用,减少重复开发。
- 解耦:降低系统各模块间的耦合度。提高系统内聚性,便于单元测试。便于后续替换和升级实现。
3.2 缺点
- 复杂性提升:增加类数量,系统结构更复杂。适配器过多时难以维护。可能引入额外的理解和调试成本。
- 性能开销:适配过程可能带来性能损耗。适配器层级过多影响响应速度。内存占用略有增加。
- 适用范围有限:只适用于接口不兼容的场景。不能解决所有系统集成问题。适配器本身功能有限,不能滥用。
4. 实际应用案例
- 系统集成:新旧系统对接(如ERP系统升级,需兼容老接口)、第三方服务接入(如支付、短信、地图等外部API)、数据格式转换(如XML与JSON互转)。
- UI框架:组件适配(如不同UI库的按钮、输入框适配)、样式转换(如主题切换、皮肤适配)、事件处理(如不同事件模型的统一)。
- 数据库访问:驱动适配(如JDBC与NoSQL数据库的适配)、方言转换(如SQL语句在不同数据库间的适配)、连接池适配(如不同连接池实现的统一接口)。
- 网络通信:协议转换(如HTTP与WebSocket、MQTT等协议适配)、数据格式适配(如Protobuf与JSON、XML互转)、安全适配(如加密、认证方式的适配)。
5. 结构与UML类图
@startuml
package "Adapter Pattern" #DDDDDD {
interface Target {
+ request(): void
}
class Adaptee {
+ specificRequest(): void
}
class ClassAdapter extends Adaptee implements Target
class ObjectAdapter implements Target {
- adaptee: Adaptee
+ request(): void
}
Target <|.. ClassAdapter
Target <|.. ObjectAdapter
ObjectAdapter o-- Adaptee : adaptee
note right: 支持类适配器和对象适配器两种实现
}
@enduml
6. 代码示例
6.1 基本结构示例
业务背景: 实现新旧系统接口适配,通过适配器模式解决接口不兼容问题。
package com.example.patterns.adapter;
import java.util.Objects;
// 目标接口,客户端期望的接口
public interface Target {
/**
* 客户端期望的方法
* 业务含义:新系统统一调用入口
*/
void request();
}
// 适配者类,已有的老系统类,接口不兼容
public class Adaptee {
/**
* 老系统的特殊方法
* 业务含义:老系统原有功能,无法直接被新系统调用
*/
public void specificRequest() {
System.out.println("Adaptee specific request - 老系统业务逻辑执行");
}
/**
* 老系统的其他方法,展示复杂性
*/
public String getData() {
return "老系统数据";
}
}
// 类适配器:通过继承实现适配(仅适用于单继承语言)
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
// 适配,将Target接口的调用转为Adaptee的specificRequest
// 业务说明:新系统调用request时,实际执行老系统逻辑
try {
specificRequest();
// 可以在适配过程中增加额外逻辑
System.out.println("Class Adapter: 数据=" + getData());
} catch (Exception e) {
System.err.println("Class Adapter failed: " + e.getMessage());
throw new RuntimeException("适配器执行失败", e);
}
}
}
// 对象适配器:通过组合实现适配,推荐方式
public class ObjectAdapter implements Target {
private final Adaptee adaptee;
/**
* 构造方法注入老系统对象,便于解耦和扩展
*/
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = Objects.requireNonNull(adaptee, "Adaptee cannot be null");
}
@Override
public void request() {
try {
// 适配,将Target接口的调用转为Adaptee的specificRequest
adaptee.specificRequest();
// 可以组合多个adaptee的方法
String data = adaptee.getData();
System.out.println("Object Adapter: 处理数据=" + data);
} catch (Exception e) {
System.err.println("Object Adapter failed: " + e.getMessage());
throw new RuntimeException("对象适配器执行失败", e);
}
}
}
6.2 企业级应用场景:支付系统适配
业务背景: 电商平台需要集成多家第三方支付平台(支付宝、微信、银联),但各平台接口不统一,通过适配器统一支付接口。
package com.example.patterns.adapter.payment;
import java.math.BigDecimal;
import java.util.Map;
import java.util.HashMap;
// 统一支付接口
public interface PaymentProcessor {
/**
* 统一支付方法
* @param amount 支付金额
* @param orderId 订单ID
* @return 支付结果
*/
PaymentResult processPayment(BigDecimal amount, String orderId);
}
// 支付结果封装
public class PaymentResult {
private boolean success;
private String transactionId;
private String message;
private String paymentChannel;
public PaymentResult(boolean success, String transactionId, String message, String paymentChannel) {
this.success = success;
this.transactionId = transactionId;
this.message = message;
this.paymentChannel = paymentChannel;
}
// Getter方法
public boolean isSuccess() { return success; }
public String getTransactionId() { return transactionId; }
public String getMessage() { return message; }
public String getPaymentChannel() { return paymentChannel; }
@Override
public String toString() {
return String.format("PaymentResult{success=%s, transactionId='%s', message='%s', channel='%s'}",
success, transactionId, message, paymentChannel);
}
}
// 支付宝SDK(第三方库,接口不可修改)
public class AlipaySDK {
public Map<String, Object> alipayTrade(double money, String orderNo) {
Map<String, Object> result = new HashMap<>();
if (money > 0 && orderNo != null) {
result.put("status", "SUCCESS");
result.put("trade_no", "alipay_" + System.currentTimeMillis());
result.put("msg", "支付宝支付成功");
} else {
result.put("status", "FAILED");
result.put("msg", "支付宝支付失败");
}
return result;
}
}
// 微信支付SDK(第三方库,接口不可修改)
public class WechatPaySDK {
public boolean wxPay(int amount, String outTradeNo) {
// 微信支付以分为单位
return amount > 0 && outTradeNo != null && !outTradeNo.trim().isEmpty();
}
public String getTransactionId() {
return "wx_" + System.currentTimeMillis();
}
}
// 银联支付SDK(第三方库,接口不可修改)
public class UnionPaySDK {
public String unionpayProcess(String amt, String orderId) {
if (amt != null && Double.parseDouble(amt) > 0 && orderId != null) {
return "00|union_" + System.currentTimeMillis() + "|银联支付成功";
}
return "01||银联支付失败";
}
}
// 支付宝适配器
public class AlipayAdapter implements PaymentProcessor {
private final AlipaySDK alipaySDK;
public AlipayAdapter() {
this.alipaySDK = new AlipaySDK();
}
@Override
public PaymentResult processPayment(BigDecimal amount, String orderId) {
try {
Map<String, Object> result = alipaySDK.alipayTrade(amount.doubleValue(), orderId);
boolean success = "SUCCESS".equals(result.get("status"));
String transactionId = success ? (String) result.get("trade_no") : null;
String message = (String) result.get("msg");
return new PaymentResult(success, transactionId, message, "支付宝");
} catch (Exception e) {
return new PaymentResult(false, null, "支付宝适配器异常: " + e.getMessage(), "支付宝");
}
}
}
// 微信支付适配器
public class WechatPayAdapter implements PaymentProcessor {
private final WechatPaySDK wechatPaySDK;
public WechatPayAdapter() {
this.wechatPaySDK = new WechatPaySDK();
}
@Override
public PaymentResult processPayment(BigDecimal amount, String orderId) {
try {
// 将元转换为分
int amountInCents = amount.multiply(new BigDecimal("100")).intValue();
boolean success = wechatPaySDK.wxPay(amountInCents, orderId);
String transactionId = success ? wechatPaySDK.getTransactionId() : null;
String message = success ? "微信支付成功" : "微信支付失败";
return new PaymentResult(success, transactionId, message, "微信支付");
} catch (Exception e) {
return new PaymentResult(false, null, "微信支付适配器异常: " + e.getMessage(), "微信支付");
}
}
}
// 银联支付适配器
public class UnionPayAdapter implements PaymentProcessor {
private final UnionPaySDK unionPaySDK;
public UnionPayAdapter() {
this.unionPaySDK = new UnionPaySDK();
}
@Override
public PaymentResult processPayment(BigDecimal amount, String orderId) {
try {
String result = unionPaySDK.unionpayProcess(amount.toString(), orderId);
String[] parts = result.split("\\|");
boolean success = "00".equals(parts[0]);
String transactionId = parts.length > 1 ? parts[1] : null;
String message = parts.length > 2 ? parts[2] : "银联支付处理完成";
return new PaymentResult(success, transactionId, message, "银联支付");
} catch (Exception e) {
return new PaymentResult(false, null, "银联支付适配器异常: " + e.getMessage(), "银联支付");
}
}
}
// 支付工厂,简化适配器的使用
public class PaymentAdapterFactory {
public static PaymentProcessor createPaymentProcessor(String paymentType) {
switch (paymentType.toLowerCase()) {
case "alipay":
return new AlipayAdapter();
case "wechat":
return new WechatPayAdapter();
case "unionpay":
return new UnionPayAdapter();
default:
throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
}
}
}
6.3 数据格式适配场景
业务背景: 系统需要处理多种数据格式(JSON、XML、CSV),通过适配器统一数据处理接口。
package com.example.patterns.adapter.data;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
// 统一数据处理接口
public interface DataProcessor {
/**
* 处理数据
* @param rawData 原始数据
* @return 处理后的标准格式数据
*/
List<Map<String, Object>> processData(String rawData);
}
// JSON处理器(假设已有的库)
public class JsonProcessor {
public Map<String, Object> parseJson(String json) {
// 简化的JSON解析逻辑
Map<String, Object> result = new HashMap<>();
if (json.contains("\"name\"") && json.contains("\"age\"")) {
result.put("name", "张三");
result.put("age", 25);
result.put("source", "JSON");
}
return result;
}
}
// XML处理器(假设已有的库)
public class XmlProcessor {
public String[] parseXml(String xml) {
// 简化的XML解析逻辑
if (xml.contains("<person>")) {
return new String[]{"李四", "30", "XML"};
}
return new String[]{};
}
}
// CSV处理器(假设已有的库)
public class CsvProcessor {
public List<String[]> parseCsv(String csv) {
List<String[]> result = new ArrayList<>();
String[] lines = csv.split("\n");
for (String line : lines) {
if (!line.trim().isEmpty()) {
result.add(line.split(","));
}
}
return result;
}
}
// JSON适配器
public class JsonDataAdapter implements DataProcessor {
private final JsonProcessor jsonProcessor;
public JsonDataAdapter() {
this.jsonProcessor = new JsonProcessor();
}
@Override
public List<Map<String, Object>> processData(String rawData) {
List<Map<String, Object>> result = new ArrayList<>();
try {
Map<String, Object> parsed = jsonProcessor.parseJson(rawData);
if (!parsed.isEmpty()) {
result.add(parsed);
}
} catch (Exception e) {
System.err.println("JSON数据处理失败: " + e.getMessage());
}
return result;
}
}
// XML适配器
public class XmlDataAdapter implements DataProcessor {
private final XmlProcessor xmlProcessor;
public XmlDataAdapter() {
this.xmlProcessor = new XmlProcessor();
}
@Override
public List<Map<String, Object>> processData(String rawData) {
List<Map<String, Object>> result = new ArrayList<>();
try {
String[] parsed = xmlProcessor.parseXml(rawData);
if (parsed.length >= 3) {
Map<String, Object> data = new HashMap<>();
data.put("name", parsed[0]);
data.put("age", Integer.parseInt(parsed[1]));
data.put("source", parsed[2]);
result.add(data);
}
} catch (Exception e) {
System.err.println("XML数据处理失败: " + e.getMessage());
}
return result;
}
}
// CSV适配器
public class CsvDataAdapter implements DataProcessor {
private final CsvProcessor csvProcessor;
public CsvDataAdapter() {
this.csvProcessor = new CsvProcessor();
}
@Override
public List<Map<String, Object>> processData(String rawData) {
List<Map<String, Object>> result = new ArrayList<>();
try {
List<String[]> parsed = csvProcessor.parseCsv(rawData);
for (String[] row : parsed) {
if (row.length >= 2) {
Map<String, Object> data = new HashMap<>();
data.put("name", row[0]);
data.put("age", Integer.parseInt(row[1]));
data.put("source", "CSV");
result.add(data);
}
}
} catch (Exception e) {
System.err.println("CSV数据处理失败: " + e.getMessage());
}
return result;
}
}
// 数据处理管理器
public class DataProcessingManager {
public static DataProcessor createProcessor(String dataType) {
switch (dataType.toLowerCase()) {
case "json":
return new JsonDataAdapter();
case "xml":
return new XmlDataAdapter();
case "csv":
return new CsvDataAdapter();
default:
throw new IllegalArgumentException("不支持的数据类型: " + dataType);
}
}
}
// 客户端使用示例
public class AdapterClient {
public static void main(String[] args) {
// 支付系统示例
PaymentProcessor alipay = PaymentAdapterFactory.createPaymentProcessor("alipay");
PaymentResult result = alipay.processPayment(new BigDecimal("99.99"), "ORDER_001");
System.out.println("支付结果: " + result);
// 数据处理示例
DataProcessor jsonProcessor = DataProcessingManager.createProcessor("json");
List<Map<String, Object>> data = jsonProcessor.processData("{\"name\":\"张三\",\"age\":25}");
System.out.println("处理结果: " + data);
}
// 总结:通过适配器模式,系统可以灵活集成不同的第三方服务和数据格式,提升了系统的扩展性和维护性。
}
7. 测试用例
业务背景: 验证适配器模式的核心功能,包括基本适配、支付系统适配和数据格式适配。
public class AdapterPatternTest {
@Test
public void testClassAdapter() {
// 测试类适配器
Target target = new ClassAdapter();
target.request();
// 验证类适配器能正确调用adaptee的方法
assertTrue("类适配器应该能正确执行", true);
}
@Test
public void testObjectAdapter() {
// 测试对象适配器
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
// 验证对象适配器能正确调用adaptee的方法
assertTrue("对象适配器应该能正确执行", true);
}
@Test
public void testObjectAdapterWithNullAdaptee() {
// 测试空对象异常处理
assertThrows(NullPointerException.class, () -> {
new ObjectAdapter(null);
});
}
@Test
public void testAlipayAdapter() {
// 测试支付宝适配器
PaymentProcessor alipay = new AlipayAdapter();
PaymentResult result = alipay.processPayment(new BigDecimal("100.00"), "TEST_ORDER_001");
assertNotNull("支付结果不应为空", result);
assertTrue("支付应该成功", result.isSuccess());
assertEquals("支付渠道应为支付宝", "支付宝", result.getPaymentChannel());
assertNotNull("交易ID不应为空", result.getTransactionId());
assertTrue("交易ID应以alipay开头", result.getTransactionId().startsWith("alipay_"));
}
@Test
public void testWechatPayAdapter() {
// 测试微信支付适配器
PaymentProcessor wechatPay = new WechatPayAdapter();
PaymentResult result = wechatPay.processPayment(new BigDecimal("50.00"), "TEST_ORDER_002");
assertNotNull("支付结果不应为空", result);
assertTrue("支付应该成功", result.isSuccess());
assertEquals("支付渠道应为微信支付", "微信支付", result.getPaymentChannel());
assertNotNull("交易ID不应为空", result.getTransactionId());
assertTrue("交易ID应以wx开头", result.getTransactionId().startsWith("wx_"));
}
@Test
public void testUnionPayAdapter() {
// 测试银联支付适配器
PaymentProcessor unionPay = new UnionPayAdapter();
PaymentResult result = unionPay.processPayment(new BigDecimal("200.00"), "TEST_ORDER_003");
assertNotNull("支付结果不应为空", result);
assertTrue("支付应该成功", result.isSuccess());
assertEquals("支付渠道应为银联支付", "银联支付", result.getPaymentChannel());
assertNotNull("交易ID不应为空", result.getTransactionId());
assertTrue("交易ID应以union开头", result.getTransactionId().startsWith("union_"));
}
@Test
public void testPaymentAdapterFactory() {
// 测试支付适配器工厂
PaymentProcessor alipay = new AlipayAdapter();
PaymentProcessor wechat = new WechatPayAdapter();
PaymentProcessor unionpay = new UnionPayAdapter();
assertTrue("应该创建支付宝适配器", alipay instanceof AlipayAdapter);
assertTrue("应该创建微信支付适配器", wechat instanceof WechatPayAdapter);
assertTrue("应该创建银联支付适配器", unionpay instanceof UnionPayAdapter);
// 测试不支持的支付类型
assertThrows(IllegalArgumentException.class, () -> {
PaymentAdapterFactory.createPaymentProcessor("unknown");
});
}
@Test
public void testJsonDataAdapter() {
// 测试JSON数据适配器
DataProcessor jsonProcessor = new JsonDataAdapter();
List<Map<String, Object>> result = jsonProcessor.processData("{\"name\":\"张三\",\"age\":25}");
assertNotNull("处理结果不应为空", result);
assertEquals("应该有一条数据", 1, result.size());
Map<String, Object> data = result.get(0);
assertEquals("姓名应为张三", "张三", data.get("name"));
assertEquals("年龄应为25", 25, data.get("age"));
assertEquals("来源应为JSON", "JSON", data.get("source"));
}
@Test
public void testXmlDataAdapter() {
// 测试XML数据适配器
DataProcessor xmlProcessor = new XmlDataAdapter();
List<Map<String, Object>> result = xmlProcessor.processData("<person><name>李四</name><age>30</age></person>");
assertNotNull("处理结果不应为空", result);
assertEquals("应该有一条数据", 1, result.size());
Map<String, Object> data = result.get(0);
assertEquals("姓名应为李四", "李四", data.get("name"));
assertEquals("年龄应为30", 30, data.get("age"));
assertEquals("来源应为XML", "XML", data.get("source"));
}
@Test
public void testCsvDataAdapter() {
// 测试CSV数据适配器
DataProcessor csvProcessor = new CsvDataAdapter();
List<Map<String, Object>> result = csvProcessor.processData("王五,28\n赵六,32");
assertNotNull("处理结果不应为空", result);
assertEquals("应该有两条数据", 2, result.size());
Map<String, Object> data1 = result.get(0);
assertEquals("第一条姓名应为王五", "王五", data1.get("name"));
assertEquals("第一条年龄应为28", 28, data1.get("age"));
Map<String, Object> data2 = result.get(1);
assertEquals("第二条姓名应为赵六", "赵六", data2.get("name"));
assertEquals("第二条年龄应为32", 32, data2.get("age"));
}
@Test
public void testDataProcessingManager() {
// 测试数据处理管理器
DataProcessor jsonProcessor = DataProcessingManager.createProcessor("json");
DataProcessor xmlProcessor = DataProcessingManager.createProcessor("xml");
DataProcessor csvProcessor = DataProcessingManager.createProcessor("csv");
assertTrue("应该创建JSON适配器", jsonProcessor instanceof JsonDataAdapter);
assertTrue("应该创建XML适配器", xmlProcessor instanceof XmlDataAdapter);
assertTrue("应该创建CSV适配器", csvProcessor instanceof CsvDataAdapter);
// 测试不支持的数据类型
assertThrows(IllegalArgumentException.class, () -> {
DataProcessingManager.createProcessor("unknown");
});
}
@Test
public void testPaymentWithInvalidAmount() {
// 测试无效金额的支付
PaymentProcessor alipay = new AlipayAdapter();
PaymentResult result = alipay.processPayment(BigDecimal.ZERO, "INVALID_ORDER");
assertNotNull("支付结果不应为空", result);
assertFalse("支付应该失败", result.isSuccess());
assertEquals("支付渠道应为支付宝", "支付宝", result.getPaymentChannel());
}
@Test
public void testDataAdapterWithInvalidData() {
// 测试无效数据的处理
DataProcessor jsonProcessor = new JsonDataAdapter();
List<Map<String, Object>> result = jsonProcessor.processData("invalid json");
assertNotNull("处理结果不应为空", result);
assertTrue("应该返回空列表", result.isEmpty());
}
}
8. 常见误区与反例
8.1 常见误区
误区1 :滥用适配器模式
// 错误示例:为了统一接口而过度使用适配器 public class SimpleStringAdapter implements StringProcessor { private String value; public SimpleStringAdapter(String value) { this.value = value; } public String process() { return value.toLowerCase(); } // 简单操作不需要适配器 }
正确做法:只在接口真正不兼容时使用适配器,简单操作直接实现即可。
误区2 :适配器包含过多业务逻辑
// 错误示例:适配器中包含复杂业务逻辑 public class BadPaymentAdapter implements PaymentProcessor { public PaymentResult processPayment(BigDecimal amount, String orderId) { // 错误:在适配器中进行业务校验和处理 if (isVipUser(orderId)) { amount = amount.multiply(new BigDecimal("0.9")); // 打折逻辑 } validateOrder(orderId); // 订单校验逻辑 return thirdPartyPay(amount, orderId); } }
正确做法:适配器只做接口转换,业务逻辑应在服务层处理。
误区3 :忽略异常处理和参数校验
// 错误示例:缺少异常处理 public class UnsafeAdapter implements Target { private Adaptee adaptee; public void request() { adaptee.specificRequest(); // 可能出现NullPointerException } }
8.2 反例分析
反例1 :适配器层级过深
多个适配器嵌套使用,导致调用链路复杂,性能下降,难以调试。反例2 :适配器职责不清
一个适配器试图适配多种不相关的接口,违反单一职责原则。反例3 :硬编码适配逻辑
在适配器中硬编码转换规则,缺乏灵活性,难以扩展。
9. 最佳实践
9.1 设计原则
优先使用对象适配器 :组合优于继承,提供更好的灵活性
// 推荐:对象适配器 public class FlexibleAdapter implements Target { private final Adaptee adaptee; private final ConversionStrategy strategy; public FlexibleAdapter(Adaptee adaptee, ConversionStrategy strategy) { this.adaptee = adaptee; this.strategy = strategy; } public void request() { strategy.convert(adaptee); } }
接口设计要单一 :目标接口应简洁明确,避免接口膨胀
// 推荐:单一职责的接口 public interface PaymentProcessor { PaymentResult processPayment(BigDecimal amount, String orderId); } // 避免:职责过多的接口 public interface BadPaymentProcessor { PaymentResult processPayment(BigDecimal amount, String orderId); void sendNotification(String message); void generateReport(String orderId); void updateInventory(String productId); }
9.2 实现技巧
适配器命名规范 :统一命名模式,便于识别和维护
// 推荐的命名模式 public class AlipayAdapter implements PaymentProcessor { } // 第三方服务适配器 public class JsonDataAdapter implements DataProcessor { } // 数据格式适配器 public class LegacySystemAdapter implements ModernInterface { } // 遗留系统适配器
参数校验和异常处理 :确保适配器健壮性
// 推荐:完善的异常处理 public class RobustAdapter implements Target { private final Adaptee adaptee; public RobustAdapter(Adaptee adaptee) { this.adaptee = Objects.requireNonNull(adaptee, "Adaptee cannot be null"); } public void request() { try { adaptee.specificRequest(); } catch (Exception e) { log.error("Adapter execution failed", e); throw new AdapterException("适配器执行失败", e); } } }
使用工厂模式简化创建 :提供统一的适配器创建接口
// 推荐:工厂模式创建适配器 public class AdapterFactory { public static PaymentProcessor createPaymentAdapter(PaymentType type) { switch (type) { case ALIPAY: return new AlipayAdapter(); case WECHAT: return new WechatPayAdapter(); case UNIONPAY: return new UnionPayAdapter(); default: throw new IllegalArgumentException("Unsupported type: " + type); } } }
9.3 性能优化
缓存和资源复用 :避免重复创建昂贵对象
// 推荐:缓存适配器实例 public class CachedAdapterFactory { private static final Map<String, PaymentProcessor> CACHE = new ConcurrentHashMap<>(); public static PaymentProcessor getPaymentAdapter(String type) { return CACHE.computeIfAbsent(type, key -> createAdapter(key)); } }
懒加载和延迟初始化 :按需创建适配器
// 推荐:懒加载适配器 public class LazyAdapter implements Target { private volatile Adaptee adaptee; private final Supplier<Adaptee> adapteeSupplier; public LazyAdapter(Supplier<Adaptee> adapteeSupplier) { this.adapteeSupplier = adapteeSupplier; } public void request() { if (adaptee == null) { synchronized(this) { if (adaptee == null) { adaptee = adapteeSupplier.get(); } } } adaptee.specificRequest(); } }
9.4 架构考虑
配置化适配规则 :通过配置管理适配逻辑
// 推荐:配置化适配 @Component public class ConfigurableAdapter { @Value("${adapter.payment.alipay.endpoint}") private String alipayEndpoint; @Value("${adapter.payment.timeout:5000}") private int timeout; }
监控和日志 :记录适配过程,便于问题排查
// 推荐:完善的监控日志 public class MonitoredAdapter implements Target { private static final Logger log = LoggerFactory.getLogger(MonitoredAdapter.class); private final MeterRegistry meterRegistry; public void request() { Timer.Sample sample = Timer.start(meterRegistry); try { log.debug("Starting adapter request"); adaptee.specificRequest(); log.info("Adapter request completed successfully"); } catch (Exception e) { log.error("Adapter request failed", e); meterRegistry.counter("adapter.errors").increment(); throw e; } finally { sample.stop(Timer.builder("adapter.request.duration").register(meterRegistry)); } } }
版本兼容性管理 :支持多版本接口适配
// 推荐:版本化适配器 public interface VersionedAdapter { boolean supports(String version); PaymentResult processPayment(BigDecimal amount, String orderId, String version); }
10. 参考资料与延伸阅读
- 《设计模式:可复用面向对象软件的基础》GoF
- Effective Java(中文版)
- https://refactoringguru.cn/design-patterns/adapter
- https://www.baeldung.com/java-adapter-pattern
本文为设计模式系列第9篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。