设计模式系列(09):结构型模式 - 适配器模式
系列导读:完成创建型模式后,我们进入结构型模式的学习。适配器模式是结构型模式的开篇,解决接口不兼容的问题。
解决什么问题:将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。用于系统集成和第三方库对接。
在软件开发中,我们经常需要使用第三方库或者对接外部系统,但它们的接口往往与我们的系统不兼容。比如,老系统使用XML格式数据,新系统使用JSON格式;或者需要集成的支付接口与现有的支付抽象不匹配。
适配器模式就像现实中的转换插头一样,让不匹配的接口能够正常工作。它在不修改原有代码的前提下,通过一个适配器类来桥接两个不兼容的接口。
本文在系列中的位置:
- 前置知识:创建型模式:原型模式
- 系列角色:结构型模式入门
- 难度等级:★★☆☆☆(概念简单,实用性强)
- 后续学习:桥接模式
目录
- 1. 模式概述
- 2. 使用场景
- 3. 优缺点分析
- 4. 实际应用案例
- 5. 结构与UML类图
- 6. 代码示例
- 7. 测试用例
- 8. 常见误区与反例
- 9. 最佳实践
- 10. 参考资料与延伸阅读
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 Targetclass ObjectAdapter implements Target {- adaptee: Adaptee+ request(): void}Target <|.. ClassAdapterTarget <|.. ObjectAdapterObjectAdapter o-- Adaptee : adapteenote 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 {@Overridepublic 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");}@Overridepublic void request() {try {// 适配,将Target接口的调用转为Adaptee的specificRequestadaptee.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; }@Overridepublic 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();}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic 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 {@Testpublic void testClassAdapter() {// 测试类适配器Target target = new ClassAdapter();target.request();// 验证类适配器能正确调用adaptee的方法assertTrue("类适配器应该能正确执行", true);}@Testpublic void testObjectAdapter() {// 测试对象适配器Adaptee adaptee = new Adaptee();Target target = new ObjectAdapter(adaptee);target.request();// 验证对象适配器能正确调用adaptee的方法assertTrue("对象适配器应该能正确执行", true);}@Testpublic void testObjectAdapterWithNullAdaptee() {// 测试空对象异常处理assertThrows(NullPointerException.class, () -> {new ObjectAdapter(null);});}@Testpublic 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_"));}@Testpublic 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_"));}@Testpublic 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_"));}@Testpublic 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");});}@Testpublic 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"));}@Testpublic 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"));}@Testpublic 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"));}@Testpublic 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");});}@Testpublic void testPaymentWithInvalidAmount() {// 测试无效金额的支付PaymentProcessor alipay = new AlipayAdapter();PaymentResult result = alipay.processPayment(BigDecimal.ZERO, "INVALID_ORDER");assertNotNull("支付结果不应为空", result);assertFalse("支付应该失败", result.isSuccess());assertEquals("支付渠道应为支付宝", "支付宝", result.getPaymentChannel());}@Testpublic 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篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。