适配器模式(Adapter Pattern):兼容转换的艺术
✨ 模式简介
适配器模式是一种结构型设计模式,它允许不兼容的接口之间能够协同工作,就像电源插头转换器让不同标准的插头能在同一插座上使用。
该模式通过包装对象的方式,将被适配者的接口转换成目标接口。
📦 应用场景
旧系统接口改造(遗留系统适配)
第三方库/组件集成
统一多个类的不一致接口
数据格式转换(如JSON ↔ XML)
SLF4J日志门面适配各种日志框架
Spring MVC的
HandlerAdapter
🧠 核心实现思路
Target(目标接口):客户端期望的接口
Adaptee(被适配者):需要被适配的现存接口
Adapter(适配器):实现目标接口并包装被适配者
🧱 适配器模式的三种实现方式
1. 类适配器(继承方式)
// 目标接口(新接口)
interface ModernPrinter {
void printDocument(String content);
}
// 被适配者(旧类)
class LegacyPrinter {
public void print(String text, int copies) {
for (int i = 0; i < copies; i++) {
System.out.println("Legacy Printing: " + text);
}
}
}
// 适配器(继承被适配者)
class PrinterAdapter extends LegacyPrinter implements ModernPrinter {
@Override
public void printDocument(String content) {
// 适配逻辑:固定copies=1
super.print(content, 1);
}
}
// 使用
ModernPrinter printer = new PrinterAdapter();
printer.printDocument("Hello Adapter");
2. 对象适配器(组合方式 - 推荐)
// 适配器(组合被适配者)
class PrinterAdapter implements ModernPrinter {
private final LegacyPrinter legacyPrinter;
public PrinterAdapter(LegacyPrinter printer) {
this.legacyPrinter = printer;
}
@Override
public void printDocument(String content) {
legacyPrinter.print(content, 1);
}
}
// 使用
ModernPrinter printer = new PrinterAdapter(new LegacyPrinter());
3. 接口适配器(缺省适配 - 抽象类)
// 复杂接口
interface ComplexService {
void save();
void update();
void delete();
void query();
}
// 缺省适配器(空实现)
abstract class ServiceAdapter implements ComplexService {
public void save() {}
public void update() {}
public void delete() {}
public void query() {}
}
// 按需实现部分方法
class CustomService extends ServiceAdapter {
@Override
public void save() {
System.out.println("仅实现save方法");
}
}
💎 最佳实践推荐
Spring中的HandlerAdapter
// 模拟Spring MVC的适配器
interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpRequest request, Object handler);
}
// Controller适配器
class AnnotationHandlerAdapter implements HandlerAdapter {
public boolean supports(Object handler) {
return handler instanceof MyController;
}
public ModelAndView handle(HttpRequest request, Object handler) {
MyController controller = (MyController)handler;
return controller.process(request);
}
}
// 使用适配器调度
public class DispatcherServlet {
private List<HandlerAdapter> adapters;
public ModelAndView dispatch(HttpRequest request, Object handler) {
for (HandlerAdapter adapter : adapters) {
if (adapter.supports(handler)) {
return adapter.handle(request, handler);
}
}
throw new RuntimeException("No adapter found");
}
}
函数式适配(Java8+)
// 旧式接口
interface OldService {
String execute(int code);
}
// 新式函数接口
@FunctionalInterface
interface NewService {
Optional<String> process(String input);
}
// 适配器工厂
class ServiceAdapters {
public static NewService adapt(OldService old) {
return input -> {
try {
int code = Integer.parseInt(input);
return Optional.ofNullable(old.execute(code));
} catch (Exception e) {
return Optional.empty();
}
};
}
}
// 使用
OldService old = code -> "Result-" + code;
NewService adapted = ServiceAdapters.adapt(old);
adapted.process("123").ifPresent(System.out::println);
💣 常见问题与解决方案
问题1:适配器过多导致混乱?
✅ 解决方案:
使用自动适配器发现机制(如Spring的
HandlerAdapter
)建立清晰的适配器命名规范(
XxxToYxxAdapter
)
问题2:需要双向适配?
✅ 解决方案:
实现双向接口
class TwoWayAdapter implements NewService, OldService {
// 实现两个接口的方法...
}
问题3:性能开销?
✅ 解决方案:
缓存适配器实例
避免深层嵌套适配(如适配器套适配器)
📊 模式对比
📚 实际应用案例
日志门面适配
// SLF4J适配Log4j Logger logger = LoggerFactory.getLogger(MyClass.class); // 实际绑定org.slf4j.impl.Log4jLoggerAdapter
JDBC驱动适配
Connection conn = DriverManager.getConnection(url); // 不同数据库有各自的驱动适配器
Java集合转换
String[] arr = {"a", "b"}; List<String> list = Arrays.asList(arr); // 数组转List的适配器
🎯 总结建议
优先选择:对象适配器(组合优于继承)
接口设计:尽量保持目标接口简洁
避免过度:不要用适配器掩盖设计缺陷
性能注意:高频调用场景考虑直接改造接口
命名规范:明确体现适配方向(如
LegacyToModernAdapter
)