适配器模式
定义
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口能够一起工作。适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
核心思想
- 接口转换:将一个类的接口转换成客户期望的另一个接口
- 兼容性:让不兼容的类能够合作
- 封装差异:隐藏不同系统之间的差异
结构
角色组成
- Target(目标接口):客户期望的接口
- Adaptee(被适配类):需要适配的现有类
- Adapter(适配器类):实现目标接口,并持有被适配类的引用
- Client(客户端):使用目标接口的类
类图
┌─────────────────┐ ┌──────────────────┐
│ Client │ │ Target │
├─────────────────┤ ├──────────────────┤
│ │───▶│ + request() │
└─────────────────┘ └──────────────────┘
▲
│
┌──────────────────┐
│ Adapter │
├──────────────────┤
│ - adaptee │
├──────────────────┤
│ + request() │
└──────────────────┘
│
▼
┌──────────────────┐
│ Adaptee │
├──────────────────┤
│ + specificRequest()│
└──────────────────┘
代码示例
场景一:第三方支付接口适配
电商系统需要集成多个第三方支付平台,但每个平台的 API 接口都不同,需要统一支付接口。
1. 目标接口
public interface PaymentService {
PaymentResult pay(PaymentRequest request);
RefundResult refund(RefundRequest request);
QueryResult queryPayment(String orderId);
}
2. 被适配的第三方支付类
// 支付宝支付API
@Component
public class AlipayApi {
public AlipayResponse doPay(AlipayRequest request) {
System.out.println("调用支付宝API进行支付: " + request.getOrderId());
return new AlipayResponse("SUCCESS", "支付宝支付成功");
}
public AlipayResponse doRefund(AlipayRefundRequest request) {
System.out.println("调用支付宝API进行退款: " + request.getOrderId());
return new AlipayResponse("SUCCESS", "支付宝退款成功");
}
public AlipayResponse queryPay(AlipayQueryRequest request) {
System.out.println("调用支付宝API查询支付状态: " + request.getOrderId());
return new AlipayResponse("SUCCESS", "支付宝查询成功");
}
}
// 微信支付API
@Component
public class WechatPayApi {
public WechatPayResponse transfer(WechatPayRequest request) {
System.out.println("调用微信支付API进行转账: " + request.getOrderId());
return new WechatPayResponse("SUCCESS", "微信支付成功");
}
public WechatPayResponse reverse(WechatPayRefundRequest request) {
System.out.println("调用微信支付API进行撤销: " + request.getOrderId());
return new WechatPayResponse("SUCCESS", "微信撤销成功");
}
public WechatPayResponse checkPay(WechatPayQueryRequest request) {
System.out.println("调用微信支付API检查支付: " + request.getOrderId());
return new WechatPayResponse("SUCCESS", "微信查询成功");
}
}
// 银联支付API
@Component
public class UnionPayApi {
public UnionPayResponse charge(UnionPayRequest request) {
System.out.println("调用银联API进行扣款: " + request.getOrderId());
return new UnionPayResponse("SUCCESS", "银联扣款成功");
}
public UnionPayResponse reverse(UnionPayRefundRequest request) {
System.out.println("调用银联API进行冲正: " + request.getOrderId());
return new UnionPayResponse("SUCCESS", "银联冲正成功");
}
public UnionPayResponse inquiry(UnionPayQueryRequest request) {
System.out.println("调用银联API进行查询: " + request.getOrderId());
return new UnionPayResponse("SUCCESS", "银联查询成功");
}
}
3. 适配器类
// 支付宝适配器
@Component("alipayAdapter")
public class AlipayAdapter implements PaymentService {
@Autowired
private AlipayApi alipayApi;
@Override
public PaymentResult pay(PaymentRequest request) {
// 将统一请求转换为支付宝请求
AlipayRequest alipayRequest = new AlipayRequest();
alipayRequest.setOrderId(request.getOrderId());
alipayRequest.setAmount(request.getAmount());
alipayRequest.setCurrency(request.getCurrency());
// 调用支付宝API
AlipayResponse response = alipayApi.doPay(alipayRequest);
// 将支付宝响应转换为统一响应
return new PaymentResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public RefundResult refund(RefundRequest request) {
AlipayRefundRequest alipayRefundRequest = new AlipayRefundRequest();
alipayRefundRequest.setOrderId(request.getOrderId());
alipayRefundRequest.setRefundAmount(request.getRefundAmount());
AlipayResponse response = alipayApi.doRefund(alipayRefundRequest);
return new RefundResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public QueryResult queryPayment(String orderId) {
AlipayQueryRequest alipayQueryRequest = new AlipayQueryRequest();
alipayQueryRequest.setOrderId(orderId);
AlipayResponse response = alipayApi.queryPay(alipayQueryRequest);
return new QueryResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
orderId
);
}
}
// 微信支付适配器
@Component("wechatPayAdapter")
public class WechatPayAdapter implements PaymentService {
@Autowired
private WechatPayApi wechatPayApi;
@Override
public PaymentResult pay(PaymentRequest request) {
WechatPayRequest wechatPayRequest = new WechatPayRequest();
wechatPayRequest.setOrderId(request.getOrderId());
wechatPayRequest.setAmount(request.getAmount());
wechatPayRequest.setCurrency(request.getCurrency());
WechatPayResponse response = wechatPayApi.transfer(wechatPayRequest);
return new PaymentResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public RefundResult refund(RefundRequest request) {
WechatPayRefundRequest wechatPayRefundRequest = new WechatPayRefundRequest();
wechatPayRefundRequest.setOrderId(request.getOrderId());
wechatPayRefundRequest.setRefundAmount(request.getRefundAmount());
WechatPayResponse response = wechatPayApi.reverse(wechatPayRefundRequest);
return new RefundResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public QueryResult queryPayment(String orderId) {
WechatPayQueryRequest wechatPayQueryRequest = new WechatPayQueryRequest();
wechatPayQueryRequest.setOrderId(orderId);
WechatPayResponse response = wechatPayApi.checkPay(wechatPayQueryRequest);
return new QueryResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
orderId
);
}
}
// 银联支付适配器
@Component("unionPayAdapter")
public class UnionPayAdapter implements PaymentService {
@Autowired
private UnionPayApi unionPayApi;
@Override
public PaymentResult pay(PaymentRequest request) {
UnionPayRequest unionPayRequest = new UnionPayRequest();
unionPayRequest.setOrderId(request.getOrderId());
unionPayRequest.setAmount(request.getAmount());
unionPayRequest.setCurrency(request.getCurrency());
UnionPayResponse response = unionPayApi.charge(unionPayRequest);
return new PaymentResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public RefundResult refund(RefundRequest request) {
UnionPayRefundRequest unionPayRefundRequest = new UnionPayRefundRequest();
unionPayRefundRequest.setOrderId(request.getOrderId());
unionPayRefundRequest.setRefundAmount(request.getRefundAmount());
UnionPayResponse response = unionPayApi.reverse(unionPayRefundRequest);
return new RefundResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
request.getOrderId()
);
}
@Override
public QueryResult queryPayment(String orderId) {
UnionPayQueryRequest unionPayQueryRequest = new UnionPayQueryRequest();
unionPayQueryRequest.setOrderId(orderId);
UnionPayResponse response = unionPayApi.inquiry(unionPayQueryRequest);
return new QueryResult(
response.getCode().equals("SUCCESS"),
response.getMessage(),
orderId
);
}
}
4. 支付服务工厂
@Service
public class PaymentServiceFactory {
@Autowired
private Map<String, PaymentService> paymentServiceMap;
public PaymentService getPaymentService(String paymentType) {
String beanName = paymentType.toLowerCase() + "Adapter";
PaymentService service = paymentServiceMap.get(beanName);
if (service == null) {
throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
}
return service;
}
}
5. 控制器
@RestController
@RequestMapping("/api/payment")
public class PaymentController {
@Autowired
private PaymentServiceFactory paymentServiceFactory;
@PostMapping("/pay")
public ResponseEntity<PaymentResult> pay(@RequestBody PaymentRequest request) {
PaymentService paymentService = paymentServiceFactory.getPaymentService(request.getPaymentType());
PaymentResult result = paymentService.pay(request);
return ResponseEntity.ok(result);
}
@PostMapping("/refund")
public ResponseEntity<RefundResult> refund(@RequestBody RefundRequest request) {
PaymentService paymentService = paymentServiceFactory.getPaymentService(request.getPaymentType());
RefundResult result = paymentService.refund(request);
return ResponseEntity.ok(result);
}
@GetMapping("/query/{orderId}")
public ResponseEntity<QueryResult> queryPayment(@PathVariable String orderId,
@RequestParam String paymentType) {
PaymentService paymentService = paymentServiceFactory.getPaymentService(paymentType);
QueryResult result = paymentService.queryPayment(orderId);
return ResponseEntity.ok(result);
}
}
场景二:消息推送适配器
系统需要支持多种消息推送方式(邮件、短信、微信、钉钉),但每个平台的 API 都不同。
1. 目标接口
public interface MessageService {
MessageResult sendMessage(MessageRequest request);
boolean isSupported(String messageType);
}
2. 被适配的消息服务
// 邮件服务
@Component
public class EmailService {
public EmailResult sendEmail(EmailRequest request) {
System.out.println("发送邮件到: " + request.getTo() + ", 主题: " + request.getSubject());
return new EmailResult("SUCCESS", "邮件发送成功");
}
}
// 短信服务
@Component
public class SmsService {
public SmsResult sendSms(SmsRequest request) {
System.out.println("发送短信到: " + request.getPhone() + ", 内容: " + request.getContent());
return new SmsResult("SUCCESS", "短信发送成功");
}
}
// 微信服务
@Component
public class WechatService {
public WechatResult sendWechat(WechatRequest request) {
System.out.println("发送微信消息到: " + request.getOpenId() + ", 内容: " + request.getContent());
return new WechatResult("SUCCESS", "微信消息发送成功");
}
}
// 钉钉服务
@Component
public class DingTalkService {
public DingTalkResult sendDingTalk(DingTalkRequest request) {
System.out.println("发送钉钉消息到: " + request.getUserId() + ", 内容: " + request.getContent());
return new DingTalkResult("SUCCESS", "钉钉消息发送成功");
}
}
3. 消息适配器
// 邮件适配器
@Component("emailAdapter")
public class EmailAdapter implements MessageService {
@Autowired
private EmailService emailService;
@Override
public MessageResult sendMessage(MessageRequest request) {
EmailRequest emailRequest = new EmailRequest();
emailRequest.setTo(request.getRecipient());
emailRequest.setSubject(request.getTitle());
emailRequest.setContent(request.getContent());
EmailResult result = emailService.sendEmail(emailRequest);
return new MessageResult(
result.getCode().equals("SUCCESS"),
result.getMessage(),
request.getMessageId()
);
}
@Override
public boolean isSupported(String messageType) {
return "EMAIL".equalsIgnoreCase(messageType);
}
}
// 短信适配器
@Component("smsAdapter")
public class SmsAdapter implements MessageService {
@Autowired
private SmsService smsService;
@Override
public MessageResult sendMessage(MessageRequest request) {
SmsRequest smsRequest = new SmsRequest();
smsRequest.setPhone(request.getRecipient());
smsRequest.setContent(request.getContent());
SmsResult result = smsService.sendSms(smsRequest);
return new MessageResult(
result.getCode().equals("SUCCESS"),
result.getMessage(),
request.getMessageId()
);
}
@Override
public boolean isSupported(String messageType) {
return "SMS".equalsIgnoreCase(messageType);
}
}
// 微信适配器
@Component("wechatAdapter")
public class WechatAdapter implements MessageService {
@Autowired
private WechatService wechatService;
@Override
public MessageResult sendMessage(MessageRequest request) {
WechatRequest wechatRequest = new WechatRequest();
wechatRequest.setOpenId(request.getRecipient());
wechatRequest.setContent(request.getContent());
WechatResult result = wechatService.sendWechat(wechatRequest);
return new MessageResult(
result.getCode().equals("SUCCESS"),
result.getMessage(),
request.getMessageId()
);
}
@Override
public boolean isSupported(String messageType) {
return "WECHAT".equalsIgnoreCase(messageType);
}
}
// 钉钉适配器
@Component("dingTalkAdapter")
public class DingTalkAdapter implements MessageService {
@Autowired
private DingTalkService dingTalkService;
@Override
public MessageResult sendMessage(MessageRequest request) {
DingTalkRequest dingTalkRequest = new DingTalkRequest();
dingTalkRequest.setUserId(request.getRecipient());
dingTalkRequest.setContent(request.getContent());
DingTalkResult result = dingTalkService.sendDingTalk(dingTalkRequest);
return new MessageResult(
result.getCode().equals("SUCCESS"),
result.getMessage(),
request.getMessageId()
);
}
@Override
public boolean isSupported(String messageType) {
return "DINGTALK".equalsIgnoreCase(messageType);
}
}
4. 消息服务管理器
@Service
public class MessageServiceManager {
@Autowired
private List<MessageService> messageServices;
public MessageService getMessageService(String messageType) {
return messageServices.stream()
.filter(service -> service.isSupported(messageType))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("不支持的消息类型: " + messageType));
}
public void sendMessage(MessageRequest request) {
MessageService service = getMessageService(request.getMessageType());
MessageResult result = service.sendMessage(request);
if (!result.isSuccess()) {
throw new RuntimeException("消息发送失败: " + result.getMessage());
}
}
}
运行结果
支付接口测试
调用支付宝API进行支付: ORDER001
调用微信支付API进行转账: ORDER002
调用银联API进行扣款: ORDER003
消息推送测试
发送邮件到: user@example.com, 主题: 订单确认
发送短信到: 13800138000, 内容: 您的订单已确认
发送微信消息到: openid123, 内容: 订单状态更新
发送钉钉消息到: user123, 内容: 系统通知
优点
- 接口统一:将不同的接口统一为客户端期望的接口
- 代码复用:可以复用现有的类,无需修改原有代码
- 扩展性好:可以轻松添加新的适配器来支持新的接口
- 解耦合:客户端与具体实现解耦
- 符合开闭原则:对扩展开放,对修改关闭
缺点
- 复杂性增加:引入了额外的抽象层
- 性能开销:适配器会带来一定的性能损失
- 过度使用:如果过度使用,可能导致系统变得复杂
- 调试困难:多层适配可能导致调试困难
应用场景
- 第三方服务集成:集成不同厂商的支付、短信、邮件等服务
- 数据库适配:支持多种数据库(MySQL、Oracle、PostgreSQL 等)
- 文件格式转换:支持多种文件格式的读写
- API 版本兼容:处理不同版本的 API 接口
- 硬件设备适配:适配不同的硬件设备接口
- 消息队列适配:支持多种消息队列(RabbitMQ、Kafka、ActiveMQ 等)
与其他模式的关系
- 与装饰器模式区别:适配器模式改变接口,装饰器模式增强功能
- 与外观模式区别:适配器模式适配一个类,外观模式简化多个类的接口
- 与代理模式区别:适配器模式改变接口,代理模式控制访问
最佳实践
- 接口设计:确保目标接口足够抽象,能够适应未来的扩展
- 错误处理:在适配器中正确处理被适配类的异常
- 性能考虑:避免在适配器中做复杂的转换操作
- 测试策略:为每个适配器编写独立的单元测试
- 文档维护:保持适配器接口的文档更新
总结
适配器模式是一种非常实用的结构型设计模式,它通过接口转换让不兼容的类能够合作。在实际开发中,适配器模式经常用于集成第三方服务、支持多种数据源、处理不同版本的 API 等场景。通过合理使用适配器模式,可以提高系统的可维护性和扩展性,降低系统间的耦合度。
