深入理解设计模式之适配器模式(Adapter Pattern)
一、引言
在软件开发中,我们经常遇到这样的问题:已有的类接口与需要的接口不匹配。比如你有一个欧标插头的电器,但酒店只提供美标插座;或者你需要整合一个第三方SDK,但它的接口与你的系统不兼容。这时,适配器模式就派上用场了。
适配器模式就像现实中的电源转换器,它充当两个不兼容接口之间的桥梁,使得原本无法协同工作的类可以一起工作。本文将深入探讨适配器模式的原理、实现方式,并结合Spring、JDBC等实际框架应用,帮助你全面掌握这一重要的设计模式。
二、什么是适配器模式
2.1 定义
适配器模式(Adapter Pattern)是一种结构型设计模式,它将一个类的接口转换成客户端期望的另一个接口。适配器让原本接口不兼容的类可以相互合作。
2.2 核心思想
- 接口转换:将一个接口转换为另一个接口
- 复用现有类:不修改现有代码的前提下实现兼容
- 解耦:客户端与被适配者解耦
- 两个方向:可以将新接口适配到旧系统,也可以将旧接口适配到新系统
2.3 模式结构
scss
客户端使用的接口:
┌──────────────────────┐
│ <<interface>> │
│ Target │ 目标接口(客户端期望的)
├──────────────────────┤
│ + request() │
└──────────────────────┘
△
│ 实现
│
┌─────┴──────────────────┐
│ │
┌────┴────────┐ ┌────────┴─────────┐
│ Adapter │ │ Adaptee │ 被适配者(已存在的类)
├─────────────┤ ├──────────────────┤
│- adaptee │◆────→│+ specificRequest │ 特殊的方法
│+ request() │ └──────────────────┘
└─────────────┘
│
└→ 调用adaptee.specificRequest()
2.4 适配器模式的三种形式
1. 类适配器(使用继承):
markdown
┌───────────┐ ┌──────────┐
│ Target │ │ Adaptee │
└─────△─────┘ └────△─────┘
│ │
│ │
└────┬────────────┘
│ 多重继承
┌────┴─────┐
│ Adapter │
└──────────┘
注:Java不支持多重继承,所以通常使用接口+类继承
2. 对象适配器(使用组合,推荐):
markdown
┌───────────┐ ┌──────────┐
│ Target │ │ Adaptee │
└─────△─────┘ └──────────┘
│ △
│ │组合
│ ┌────┴─────┐
│ │ │
└────────────┤ Adapter │
└──────────┘
3. 接口适配器(缺省适配器):
scss
┌────────────────────┐
│ <<interface>> │
│ MultiMethod │ 多方法接口
├────────────────────┤
│+ method1() │
│+ method2() │
│+ method3() │
│+ method4() │
└─────────△──────────┘
│
┌─────┴─────┐
│ Abstract │ 抽象适配器(提供空实现)
│ Adapter │
└─────△─────┘
│
│
┌─────┴──────┐
│ Concrete │ 具体类只需实现需要的方法
│ Adapter │
└────────────┘
三、基础示例
3.1 场景:电源适配器
最经典的例子:中国电器(220V)需要在日本(110V)使用。
目标接口(客户端期望):
java
/**
* 目标接口:日本电源插座(110V)
*/
public interface JapanesePlug {
/**
* 提供110V电压
*/
void provide110V();
}
被适配者(已存在的类):
java
/**
* 被适配者:中国电器(需要220V)
*/
public class ChineseAppliance {
private String name;
public ChineseAppliance(String name) {
this.name = name;
}
/**
* 使用220V电压工作
*/
public void use220V() {
System.out.println(name + " 正在使用220V电压工作");
}
public String getName() {
return name;
}
}
对象适配器:
java
/**
* 对象适配器:电源适配器(推荐方式)
* 将220V的中国电器适配到110V的日本插座
*/
public class PowerAdapter implements JapanesePlug {
private ChineseAppliance chineseAppliance;
public PowerAdapter(ChineseAppliance chineseAppliance) {
this.chineseAppliance = chineseAppliance;
}
@Override
public void provide110V() {
System.out.println("电源适配器工作中:将110V转换为220V");
// 调用被适配者的方法
chineseAppliance.use220V();
}
}
类适配器(Java中使用接口+继承):
java
/**
* 类适配器:通过继承实现适配
*/
public class PowerAdapterByInheritance extends ChineseAppliance implements JapanesePlug {
public PowerAdapterByInheritance(String name) {
super(name);
}
@Override
public void provide110V() {
System.out.println("电源适配器工作中(类适配器):将110V转换为220V");
// 直接调用父类方法
use220V();
}
}
客户端使用:
java
public class PowerAdapterDemo {
public static void main(String[] args) {
System.out.println("=== 场景1:使用对象适配器 ===");
// 中国电器
ChineseAppliance laptop = new ChineseAppliance("笔记本电脑");
// 使用适配器,让中国电器在日本使用
JapanesePlug adapter = new PowerAdapter(laptop);
adapter.provide110V();
System.out.println("\n=== 场景2:使用类适配器 ===");
JapanesePlug adapter2 = new PowerAdapterByInheritance("电吹风");
adapter2.provide110V();
}
}
输出:
diff
=== 场景1:使用对象适配器 ===
电源适配器工作中:将110V转换为220V
笔记本电脑 正在使用220V电压工作
=== 场景2:使用类适配器 ===
电源适配器工作中(类适配器):将110V转换为220V
电吹风 正在使用220V电压工作
3.2 场景:读卡器(多种适配器)
读卡器可以读取不同类型的存储卡。
java
/**
* 目标接口:通用存储设备
*/
public interface StorageDevice {
String readData();
void writeData(String data);
}
/**
* 被适配者1:SD卡
*/
public class SDCard {
public String readSD() {
return "SD卡数据";
}
public void writeSD(String data) {
System.out.println("写入SD卡: " + data);
}
}
/**
* 被适配者2:TF卡(Micro SD)
*/
public class TFCard {
public String readTF() {
return "TF卡数据";
}
public void writeTF(String data) {
System.out.println("写入TF卡: " + data);
}
}
/**
* 被适配者3:Memory Stick
*/
public class MemoryStick {
public String readMS() {
return "Memory Stick数据";
}
public void writeMS(String data) {
System.out.println("写入Memory Stick: " + data);
}
}
/**
* SD卡适配器
*/
public class SDCardAdapter implements StorageDevice {
private SDCard sdCard;
public SDCardAdapter(SDCard sdCard) {
this.sdCard = sdCard;
}
@Override
public String readData() {
return sdCard.readSD();
}
@Override
public void writeData(String data) {
sdCard.writeSD(data);
}
}
/**
* TF卡适配器
*/
public class TFCardAdapter implements StorageDevice {
private TFCard tfCard;
public TFCardAdapter(TFCard tfCard) {
this.tfCard = tfCard;
}
@Override
public String readData() {
return tfCard.readTF();
}
@Override
public void writeData(String data) {
tfCard.writeTF(data);
}
}
/**
* Memory Stick适配器
*/
public class MemoryStickAdapter implements StorageDevice {
private MemoryStick memoryStick;
public MemoryStickAdapter(MemoryStick memoryStick) {
this.memoryStick = memoryStick;
}
@Override
public String readData() {
return memoryStick.readMS();
}
@Override
public void writeData(String data) {
memoryStick.writeMS(data);
}
}
/**
* 客户端:电脑(只认识通用存储设备接口)
*/
public class Computer {
public void readStorage(StorageDevice storage) {
String data = storage.readData();
System.out.println("电脑读取到: " + data);
}
public void writeStorage(StorageDevice storage, String data) {
storage.writeData(data);
System.out.println("电脑写入完成");
}
}
/**
* 测试类
*/
public class CardReaderDemo {
public static void main(String[] args) {
Computer computer = new Computer();
// 使用SD卡
System.out.println("=== 使用SD卡 ===");
SDCard sdCard = new SDCard();
StorageDevice sdAdapter = new SDCardAdapter(sdCard);
computer.readStorage(sdAdapter);
computer.writeStorage(sdAdapter, "文档.doc");
// 使用TF卡
System.out.println("\n=== 使用TF卡 ===");
TFCard tfCard = new TFCard();
StorageDevice tfAdapter = new TFCardAdapter(tfCard);
computer.readStorage(tfAdapter);
// 使用Memory Stick
System.out.println("\n=== 使用Memory Stick ===");
MemoryStick ms = new MemoryStick();
StorageDevice msAdapter = new MemoryStickAdapter(ms);
computer.readStorage(msAdapter);
}
}
四、实际生产场景应用
4.1 场景:第三方支付适配器
系统需要集成多个支付渠道(支付宝、微信、银联),但它们的API各不相同。
java
/**
* 目标接口:统一支付接口
*/
public interface PaymentProcessor {
/**
* 支付
* @param orderId 订单号
* @param amount 金额
* @return 支付结果
*/
PaymentResult pay(String orderId, double amount);
/**
* 退款
* @param orderId 订单号
* @param amount 金额
* @return 退款结果
*/
PaymentResult refund(String orderId, double amount);
/**
* 查询订单
* @param orderId 订单号
* @return 订单状态
*/
String queryOrder(String orderId);
}
/**
* 支付结果
*/
class PaymentResult {
private boolean success;
private String message;
private String transactionId;
public PaymentResult(boolean success, String message, String transactionId) {
this.success = success;
this.message = message;
this.transactionId = transactionId;
}
// Getters
public boolean isSuccess() { return success; }
public String getMessage() { return message; }
public String getTransactionId() { return transactionId; }
@Override
public String toString() {
return "PaymentResult{" +
"success=" + success +
", message='" + message + '\'' +
", transactionId='" + transactionId + '\'' +
'}';
}
}
被适配者:各第三方支付SDK
java
/**
* 被适配者1:支付宝SDK(假设的API)
*/
public class AlipaySDK {
public AlipayResponse trade(String outTradeNo, String amount) {
System.out.println("[支付宝] 发起支付: 订单=" + outTradeNo + ", 金额=" + amount);
// 模拟支付成功
AlipayResponse response = new AlipayResponse();
response.code = "10000";
response.msg = "Success";
response.tradeNo = "2025" + System.currentTimeMillis();
return response;
}
public AlipayResponse refundTrade(String outTradeNo, String refundAmount) {
System.out.println("[支付宝] 发起退款: 订单=" + outTradeNo + ", 金额=" + refundAmount);
AlipayResponse response = new AlipayResponse();
response.code = "10000";
response.msg = "Refund Success";
response.tradeNo = "R" + System.currentTimeMillis();
return response;
}
public AlipayResponse query(String outTradeNo) {
System.out.println("[支付宝] 查询订单: " + outTradeNo);
AlipayResponse response = new AlipayResponse();
response.code = "10000";
response.tradeStatus = "TRADE_SUCCESS";
return response;
}
// 支付宝响应对象
public static class AlipayResponse {
public String code;
public String msg;
public String tradeNo;
public String tradeStatus;
}
}
/**
* 被适配者2:微信支付SDK(假设的API)
*/
public class WeChatPaySDK {
public WeChatPayResult unifiedOrder(String orderNo, int totalFee) {
System.out.println("[微信支付] 统一下单: 订单=" + orderNo + ", 金额=" + totalFee + "分");
WeChatPayResult result = new WeChatPayResult();
result.returnCode = "SUCCESS";
result.resultCode = "SUCCESS";
result.transactionId = "WX" + System.currentTimeMillis();
return result;
}
public WeChatPayResult refundOrder(String orderNo, int refundFee) {
System.out.println("[微信支付] 申请退款: 订单=" + orderNo + ", 金额=" + refundFee + "分");
WeChatPayResult result = new WeChatPayResult();
result.returnCode = "SUCCESS";
result.resultCode = "SUCCESS";
result.refundId = "R" + System.currentTimeMillis();
return result;
}
public WeChatPayResult orderQuery(String orderNo) {
System.out.println("[微信支付] 查询订单: " + orderNo);
WeChatPayResult result = new WeChatPayResult();
result.returnCode = "SUCCESS";
result.tradeState = "SUCCESS";
return result;
}
// 微信支付响应对象
public static class WeChatPayResult {
public String returnCode;
public String resultCode;
public String transactionId;
public String refundId;
public String tradeState;
}
}
/**
* 被适配者3:银联支付SDK(假设的API)
*/
public class UnionPaySDK {
public boolean consume(String orderId, String amt) {
System.out.println("[银联支付] 消费交易: 订单=" + orderId + ", 金额=" + amt + "元");
return true;
}
public boolean refund(String orderId, String amt) {
System.out.println("[银联支付] 退货交易: 订单=" + orderId + ", 金额=" + amt + "元");
return true;
}
public String queryTrans(String orderId) {
System.out.println("[银联支付] 查询交易: " + orderId);
return "00"; // 00表示成功
}
}
适配器实现:
java
/**
* 支付宝适配器
*/
public class AlipayAdapter implements PaymentProcessor {
private AlipaySDK alipaySDK;
public AlipayAdapter() {
this.alipaySDK = new AlipaySDK();
}
@Override
public PaymentResult pay(String orderId, double amount) {
// 将amount转换为字符串格式
String amountStr = String.format("%.2f", amount);
// 调用支付宝SDK
AlipaySDK.AlipayResponse response = alipaySDK.trade(orderId, amountStr);
// 转换响应格式
boolean success = "10000".equals(response.code);
return new PaymentResult(success, response.msg, response.tradeNo);
}
@Override
public PaymentResult refund(String orderId, double amount) {
String amountStr = String.format("%.2f", amount);
AlipaySDK.AlipayResponse response = alipaySDK.refundTrade(orderId, amountStr);
boolean success = "10000".equals(response.code);
return new PaymentResult(success, response.msg, response.tradeNo);
}
@Override
public String queryOrder(String orderId) {
AlipaySDK.AlipayResponse response = alipaySDK.query(orderId);
return response.tradeStatus;
}
}
/**
* 微信支付适配器
*/
public class WeChatPayAdapter implements PaymentProcessor {
private WeChatPaySDK weChatPaySDK;
public WeChatPayAdapter() {
this.weChatPaySDK = new WeChatPaySDK();
}
@Override
public PaymentResult pay(String orderId, double amount) {
// 微信支付使用分为单位
int totalFee = (int) (amount * 100);
// 调用微信支付SDK
WeChatPaySDK.WeChatPayResult result = weChatPaySDK.unifiedOrder(orderId, totalFee);
// 转换响应格式
boolean success = "SUCCESS".equals(result.returnCode) && "SUCCESS".equals(result.resultCode);
return new PaymentResult(success, "微信支付成功", result.transactionId);
}
@Override
public PaymentResult refund(String orderId, double amount) {
int refundFee = (int) (amount * 100);
WeChatPaySDK.WeChatPayResult result = weChatPaySDK.refundOrder(orderId, refundFee);
boolean success = "SUCCESS".equals(result.returnCode);
return new PaymentResult(success, "退款成功", result.refundId);
}
@Override
public String queryOrder(String orderId) {
WeChatPaySDK.WeChatPayResult result = weChatPaySDK.orderQuery(orderId);
return result.tradeState;
}
}
/**
* 银联支付适配器
*/
public class UnionPayAdapter implements PaymentProcessor {
private UnionPaySDK unionPaySDK;
public UnionPayAdapter() {
this.unionPaySDK = new UnionPaySDK();
}
@Override
public PaymentResult pay(String orderId, double amount) {
String amountStr = String.valueOf(amount);
boolean success = unionPaySDK.consume(orderId, amountStr);
return new PaymentResult(success, success ? "支付成功" : "支付失败", orderId);
}
@Override
public PaymentResult refund(String orderId, double amount) {
String amountStr = String.valueOf(amount);
boolean success = unionPaySDK.refund(orderId, amountStr);
return new PaymentResult(success, success ? "退款成功" : "退款失败", orderId);
}
@Override
public String queryOrder(String orderId) {
String code = unionPaySDK.queryTrans(orderId);
return "00".equals(code) ? "SUCCESS" : "FAIL";
}
}
支付工厂和客户端:
java
/**
* 支付处理器工厂
*/
public class PaymentProcessorFactory {
public static PaymentProcessor getProcessor(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);
}
}
}
/**
* 订单服务(客户端)
*/
public class OrderService {
public void processPayment(String orderId, double amount, String paymentType) {
System.out.println("\n========== 处理订单支付 ==========");
System.out.println("订单号: " + orderId);
System.out.println("金额: ¥" + amount);
System.out.println("支付方式: " + paymentType);
System.out.println("================================\n");
// 获取对应的支付处理器(适配器)
PaymentProcessor processor = PaymentProcessorFactory.getProcessor(paymentType);
// 统一调用支付接口
PaymentResult result = processor.pay(orderId, amount);
System.out.println("\n支付结果: " + result);
// 查询订单状态
String status = processor.queryOrder(orderId);
System.out.println("订单状态: " + status + "\n");
}
}
/**
* 测试类
*/
public class PaymentAdapterDemo {
public static void main(String[] args) {
OrderService orderService = new OrderService();
// 使用支付宝支付
orderService.processPayment("ORDER001", 99.99, "alipay");
// 使用微信支付
orderService.processPayment("ORDER002", 199.50, "wechat");
// 使用银联支付
orderService.processPayment("ORDER003", 299.00, "unionpay");
}
}
4.2 场景:日志框架适配器
系统需要支持多种日志框架(Log4j、Logback、JDK Logging),但又希望统一使用。
java
/**
* 目标接口:统一日志接口
*/
public interface Logger {
void debug(String message);
void info(String message);
void warn(String message);
void error(String message);
}
/**
* 被适配者1:Log4j(假设的API)
*/
class Log4jLogger {
private String name;
public Log4jLogger(String name) {
this.name = name;
}
public void log(int level, String msg) {
String levelName = getLevelName(level);
System.out.println("[Log4j] " + levelName + " - " + name + ": " + msg);
}
private String getLevelName(int level) {
switch (level) {
case 0: return "DEBUG";
case 1: return "INFO";
case 2: return "WARN";
case 3: return "ERROR";
default: return "UNKNOWN";
}
}
}
/**
* 被适配者2:JDK Logging
*/
class JdkLogger {
private String name;
public JdkLogger(String name) {
this.name = name;
}
public void logp(String level, String sourceClass, String sourceMethod, String msg) {
System.out.println("[JDK] " + level + " - " + name + "." + sourceMethod + ": " + msg);
}
}
/**
* Log4j适配器
*/
public class Log4jAdapter implements Logger {
private Log4jLogger log4jLogger;
public Log4jAdapter(String name) {
this.log4jLogger = new Log4jLogger(name);
}
@Override
public void debug(String message) {
log4jLogger.log(0, message);
}
@Override
public void info(String message) {
log4jLogger.log(1, message);
}
@Override
public void warn(String message) {
log4jLogger.log(2, message);
}
@Override
public void error(String message) {
log4jLogger.log(3, message);
}
}
/**
* JDK Logging适配器
*/
public class JdkLoggerAdapter implements Logger {
private JdkLogger jdkLogger;
private String className;
public JdkLoggerAdapter(String name) {
this.jdkLogger = new JdkLogger(name);
this.className = name;
}
@Override
public void debug(String message) {
jdkLogger.logp("FINE", className, "debug", message);
}
@Override
public void info(String message) {
jdkLogger.logp("INFO", className, "info", message);
}
@Override
public void warn(String message) {
jdkLogger.logp("WARNING", className, "warn", message);
}
@Override
public void error(String message) {
jdkLogger.logp("SEVERE", className, "error", message);
}
}
/**
* 日志工厂
*/
public class LoggerFactory {
private static String loggerType = "log4j"; // 可配置
public static Logger getLogger(String name) {
if ("log4j".equals(loggerType)) {
return new Log4jAdapter(name);
} else if ("jdk".equals(loggerType)) {
return new JdkLoggerAdapter(name);
}
throw new IllegalArgumentException("不支持的日志类型");
}
public static void setLoggerType(String type) {
loggerType = type;
}
}
/**
* 测试
*/
class LoggerAdapterDemo {
public static void main(String[] args) {
// 使用Log4j
System.out.println("=== 使用Log4j ===");
LoggerFactory.setLoggerType("log4j");
Logger logger1 = LoggerFactory.getLogger("com.example.Service");
logger1.info("应用启动");
logger1.warn("内存使用率较高");
// 切换到JDK Logging
System.out.println("\n=== 切换到JDK Logging ===");
LoggerFactory.setLoggerType("jdk");
Logger logger2 = LoggerFactory.getLogger("com.example.Controller");
logger2.info("请求处理中");
logger2.error("请求处理失败");
}
}
五、开源框架中的应用
5.1 Spring MVC的HandlerAdapter
Spring MVC使用适配器模式支持多种类型的Controller。
java
/**
* Spring MVC的HandlerAdapter接口(简化版)
* 不同类型的Handler需要不同的适配器来执行
*/
public interface HandlerAdapter {
/**
* 判断是否支持该Handler
*/
boolean supports(Object handler);
/**
* 执行Handler
*/
void handle(Object handler, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
/**
* 简化的HttpServletRequest和Response
*/
class HttpServletRequest {
private java.util.Map<String, String> parameters = new java.util.HashMap<>();
public String getParameter(String name) {
return parameters.get(name);
}
public void setParameter(String name, String value) {
parameters.put(name, value);
}
}
class HttpServletResponse {
private String content;
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
/**
* 被适配者1:实现Controller接口的处理器
*/
interface Controller {
String handleRequest(HttpServletRequest request, HttpServletResponse response);
}
class UserController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
System.out.println("[Controller接口] 处理用户请求");
return "user-view";
}
}
/**
* 被适配者2:使用@RequestMapping注解的处理器
*/
class AnnotatedController {
public String getUser(String id) {
System.out.println("[注解Controller] 获取用户: " + id);
return "user-detail";
}
public String saveUser(String name) {
System.out.println("[注解Controller] 保存用户: " + name);
return "success";
}
}
/**
* 适配器1:Controller接口适配器
*/
class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof Controller;
}
@Override
public void handle(Object handler, HttpServletRequest request, HttpServletResponse response)
throws Exception {
Controller controller = (Controller) handler;
String viewName = controller.handleRequest(request, response);
response.setContent("View: " + viewName);
}
}
/**
* 适配器2:注解Controller适配器
*/
class RequestMappingHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof AnnotatedController;
}
@Override
public void handle(Object handler, HttpServletRequest request, HttpServletResponse response)
throws Exception {
AnnotatedController controller = (AnnotatedController) handler;
// 简化:根据请求路径调用不同方法
String uri = request.getParameter("uri");
String result;
if ("/getUser".equals(uri)) {
String id = request.getParameter("id");
result = controller.getUser(id);
} else if ("/saveUser".equals(uri)) {
String name = request.getParameter("name");
result = controller.saveUser(name);
} else {
result = "404";
}
response.setContent("Result: " + result);
}
}
/**
* DispatcherServlet(简化版)
*/
class DispatcherServlet {
private java.util.List<HandlerAdapter> handlerAdapters = new java.util.ArrayList<>();
public DispatcherServlet() {
// 注册所有适配器
handlerAdapters.add(new SimpleControllerHandlerAdapter());
handlerAdapters.add(new RequestMappingHandlerAdapter());
}
public void doDispatch(Object handler, HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 找到支持该Handler的适配器
HandlerAdapter adapter = getHandlerAdapter(handler);
if (adapter == null) {
throw new Exception("没有找到支持的HandlerAdapter");
}
// 使用适配器执行Handler
adapter.handle(handler, request, response);
}
private HandlerAdapter getHandlerAdapter(Object handler) {
for (HandlerAdapter adapter : handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
return null;
}
}
/**
* 测试Spring MVC适配器
*/
class SpringMVCAdapterDemo {
public static void main(String[] args) throws Exception {
DispatcherServlet servlet = new DispatcherServlet();
// 场景1:使用Controller接口
System.out.println("=== 场景1:Controller接口 ===");
Controller controller1 = new UserController();
HttpServletRequest request1 = new HttpServletRequest();
HttpServletResponse response1 = new HttpServletResponse();
servlet.doDispatch(controller1, request1, response1);
System.out.println("响应: " + response1.getContent());
// 场景2:使用注解Controller
System.out.println("\n=== 场景2:注解Controller ===");
AnnotatedController controller2 = new AnnotatedController();
HttpServletRequest request2 = new HttpServletRequest();
request2.setParameter("uri", "/getUser");
request2.setParameter("id", "123");
HttpServletResponse response2 = new HttpServletResponse();
servlet.doDispatch(controller2, request2, response2);
System.out.println("响应: " + response2.getContent());
}
}
5.2 Java I/O的InputStreamReader
InputStreamReader是字节流到字符流的适配器。
java
import java.io.*;
/**
* InputStreamReader的适配器模式
*
* InputStream (字节流) → InputStreamReader → Reader (字符流)
* (适配器)
*/
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
// InputStream只能读取字节
InputStream inputStream = new ByteArrayInputStream("Hello 世界".getBytes("UTF-8"));
// InputStreamReader将字节流适配为字符流
Reader reader = new InputStreamReader(inputStream, "UTF-8");
// 现在可以按字符读取(自动处理字符编码)
int c;
while ((c = reader.read()) != -1) {
System.out.print((char) c);
}
reader.close();
}
}
/**
* 简化的InputStreamReader实现原理
*/
class SimpleInputStreamReader extends Reader {
private InputStream inputStream;
private String charset;
public SimpleInputStreamReader(InputStream inputStream, String charset) {
this.inputStream = inputStream;
this.charset = charset;
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
// 读取字节
byte[] bytes = new byte[len];
int bytesRead = inputStream.read(bytes);
if (bytesRead == -1) {
return -1;
}
// 将字节转换为字符(适配过程)
String str = new String(bytes, 0, bytesRead, charset);
char[] chars = str.toCharArray();
// 复制到目标数组
System.arraycopy(chars, 0, cbuf, off, chars.length);
return chars.length;
}
@Override
public void close() throws IOException {
inputStream.close();
}
}
5.3 SLF4J日志门面
SLF4J通过适配器支持多种日志实现。
java
/**
* SLF4J的适配器模式
*
* SLF4J API (统一接口)
* ↓
* ┌────┴────┬────────┬─────────┐
* │ │ │ │
* Log4j Logback JDK Log 其他...
* Adapter Adapter Adapter
*
* 用户代码只依赖SLF4J接口,具体实现通过适配器桥接
*/
public class SLF4JAdapterExample {
// 简化的SLF4J Logger接口
interface Logger {
void info(String msg);
void error(String msg, Throwable t);
}
// 简化的LoggerFactory
static class LoggerFactory {
public static Logger getLogger(Class<?> clazz) {
// 根据classpath中的实现选择适配器
// 这里简化为直接返回Log4j适配器
return new Log4jLoggerAdapter(clazz.getName());
}
}
// Log4j适配器实现
static class Log4jLoggerAdapter implements Logger {
private String name;
public Log4jLoggerAdapter(String name) {
this.name = name;
}
@Override
public void info(String msg) {
// 适配到Log4j的API
System.out.println("[Log4j-Adapter] INFO " + name + ": " + msg);
}
@Override
public void error(String msg, Throwable t) {
System.out.println("[Log4j-Adapter] ERROR " + name + ": " + msg);
if (t != null) {
t.printStackTrace();
}
}
}
// 使用示例
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(SLF4JAdapterExample.class);
logger.info("应用启动");
logger.error("发生错误", new Exception("测试异常"));
}
}
5.4 Arrays.asList() - 数组到List的适配
java
import java.util.*;
/**
* Arrays.asList()将数组适配为List
*/
public class ArraysAsListDemo {
public static void main(String[] args) {
// 数组
String[] array = {"A", "B", "C"};
// Arrays.asList()将数组适配为List接口
List<String> list = Arrays.asList(array);
System.out.println("List大小: " + list.size());
System.out.println("第一个元素: " + list.get(0));
// 注意:返回的List是固定大小的,不支持add/remove
// list.add("D"); // 会抛出UnsupportedOperationException
// 但支持修改元素
list.set(0, "AA");
System.out.println("修改后: " + Arrays.toString(array)); // [AA, B, C]
}
}
/**
* 简化的Arrays.asList()实现原理
*/
class ArraysAdapter {
public static <T> List<T> asList(T[] array) {
return new ArrayList<>(array);
}
// 适配器:将数组包装为List
static class ArrayList<E> extends AbstractList<E> {
private final E[] array;
ArrayList(E[] array) {
this.array = array;
}
@Override
public E get(int index) {
return array[index];
}
@Override
public E set(int index, E element) {
E oldValue = array[index];
array[index] = element;
return oldValue;
}
@Override
public int size() {
return array.length;
}
}
}
六、适配器模式的优缺点
6.1 优点
1. 提高类的复用性
scss
无需修改现有类:
┌─────────────┐
│ ExistingClass│ (不变)
└─────────────┘
↑
│适配
┌──────┴──────┐
│ Adapter │ (新增)
└─────────────┘
↓
新的接口使用
2. 增加类的透明性
- 客户端不需要知道适配的细节
- 只需要知道目标接口
3. 灵活性好
- 可以随时替换适配器
- 不影响客户端代码
4. 符合开闭原则
- 添加新的适配器无需修改现有代码
6.2 缺点
1. 过多使用会使系统凌乱
如果有10个不同的被适配者:
→ 需要10个适配器
→ 系统结构复杂
2. 增加系统复杂度
- 引入额外的类和对象
- 增加代码量
3. 类适配器的局限性
- Java不支持多重继承
- 只能适配一个被适配者
七、适配器模式最佳实践
7.1 优先使用对象适配器
java
/**
* 推荐:对象适配器(组合)
*/
public class GoodAdapter implements Target {
private Adaptee adaptee; // 使用组合
public GoodAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
/**
* 不推荐:类适配器(继承)
* 缺点:
* 1. 破坏封装性
* 2. 只能适配一个类
* 3. 继承关系固定
*/
public class NotRecommendedAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
7.2 使用接口适配器简化实现
java
/**
* 场景:接口有很多方法,但大多数时候只需要实现其中几个
*/
interface WindowListener {
void windowOpened();
void windowClosing();
void windowClosed();
void windowIconified();
void windowDeiconified();
void windowActivated();
void windowDeactivated();
}
/**
* 接口适配器:提供默认空实现
*/
abstract class WindowAdapter implements WindowListener {
@Override
public void windowOpened() {}
@Override
public void windowClosing() {}
@Override
public void windowClosed() {}
@Override
public void windowIconified() {}
@Override
public void windowDeiconified() {}
@Override
public void windowActivated() {}
@Override
public void windowDeactivated() {}
}
/**
* 使用者只需要重写需要的方法
*/
class MyWindowListener extends WindowAdapter {
@Override
public void windowClosing() {
System.out.println("窗口正在关闭");
// 只实现这一个方法
}
}
7.3 适配器与工厂模式结合
java
/**
* 适配器工厂:统一管理适配器的创建
*/
public class AdapterFactory {
private static java.util.Map<String, Class<? extends PaymentProcessor>> adapters =
new java.util.HashMap<>();
static {
adapters.put("alipay", AlipayAdapter.class);
adapters.put("wechat", WeChatPayAdapter.class);
adapters.put("unionpay", UnionPayAdapter.class);
}
/**
* 根据类型创建适配器
*/
public static PaymentProcessor createAdapter(String type) {
Class<? extends PaymentProcessor> clazz = adapters.get(type);
if (clazz == null) {
throw new IllegalArgumentException("不支持的支付类型: " + type);
}
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("创建适配器失败", e);
}
}
/**
* 注册新的适配器
*/
public static void registerAdapter(String type, Class<? extends PaymentProcessor> adapterClass) {
adapters.put(type, adapterClass);
}
}
7.4 双向适配器
java
/**
* 双向适配器:可以在两个接口之间相互适配
*/
public class TwoWayAdapter implements Target, Adaptee {
private Target target;
private Adaptee adaptee;
public TwoWayAdapter(Target target) {
this.target = target;
}
public TwoWayAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
// 实现Target接口
@Override
public void request() {
if (adaptee != null) {
adaptee.specificRequest();
}
}
// 实现Adaptee接口
@Override
public void specificRequest() {
if (target != null) {
target.request();
}
}
}
interface Target {
void request();
}
interface Adaptee {
void specificRequest();
}
八、总结
8.1 核心要点
- 适配器模式的本质:将一个接口转换成另一个接口,使不兼容的类可以一起工作
- 三种形式 :
- 类适配器(继承)
- 对象适配器(组合,推荐)
- 接口适配器(缺省实现)
- 适用场景 :
- 系统需要使用现有的类,但接口不符
- 想创建一个可重用的类,与不相关的类协同工作
- 需要统一多个第三方库的接口
8.2 使用建议
arduino
选择适配器模式的检查清单:
✓ 是否需要使用现有类,但接口不匹配?
✓ 是否需要整合多个第三方库?
✓ 是否想在不修改源代码的情况下使用某个类?
✓ 是否需要为一组相似的类提供统一接口?
如果以上都是"是",那么适配器模式是个好选择!
8.3 与其他模式的对比
diff
适配器 vs 装饰者:
- 适配器:改变接口
- 装饰者:增强功能,不改变接口
适配器 vs 代理:
- 适配器:接口转换
- 代理:控制访问,接口相同
适配器 vs 外观模式:
- 适配器:转换一个接口
- 外观:简化多个接口
8.4 实践原则
- 优先使用对象适配器:更灵活,支持运行时替换
- 保持适配器简单:只做接口转换,不添加额外逻辑
- 结合工厂模式:统一管理适配器的创建
- 文档化:清楚说明适配的源接口和目标接口