跳到主要内容

适配器模式

问题

什么是适配器模式?Java 和 Spring 中有哪些典型应用?

答案

核心思想

将一个类的接口转换成客户端期望的另一个接口,使原本不兼容的类可以一起工作。就像电源适配器把 220V 转成 5V。

类适配器 vs 对象适配器

方式实现优缺点
类适配器继承 Adaptee + 实现 TargetJava 单继承限制
对象适配器持有 Adaptee 引用(组合)更灵活,推荐

实现示例

适配器模式 - 统一日志接口
// 目标接口:项目统一的日志接口
public interface Logger {
void info(String msg);
void error(String msg, Throwable t);
}

// 被适配者:第三方 SDK 的日志接口,方法签名不一样
public class ThirdPartyLogger {
public void log(int level, String message, Exception ex) { /* ... */ }
}

// 适配器:将第三方日志接口转换为项目统一接口
public class ThirdPartyLoggerAdapter implements Logger {
private final ThirdPartyLogger adaptee;

public ThirdPartyLoggerAdapter(ThirdPartyLogger adaptee) {
this.adaptee = adaptee;
}

@Override
public void info(String msg) {
adaptee.log(1, msg, null); // level 1 = INFO
}

@Override
public void error(String msg, Throwable t) {
adaptee.log(3, msg, (Exception) t); // level 3 = ERROR
}
}

Java/Spring 中的典型应用

应用说明
Arrays.asList()数组适配为 List 接口
InputStreamReader字节流适配为字符流
Collections.enumeration()Iterator 适配为 Enumeration
SLF4J统一日志门面,适配 Log4j/Logback 等
Spring MVC HandlerAdapter不同类型的 Controller 适配为统一处理流程
Spring MVC HandlerAdapter
// Spring MVC 的 DispatcherServlet 需要统一调用 handle()
// 但 Controller 有多种形式:@Controller、HttpRequestHandler、Servlet...
// HandlerAdapter 负责将不同类型适配为统一接口

public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Object handler);
}

// RequestMappingHandlerAdapter:处理 @RequestMapping 注解的方法
// HttpRequestHandlerAdapter:处理 HttpRequestHandler 接口
// SimpleControllerHandlerAdapter:处理 Controller 接口

常见面试问题

Q1: 适配器模式和装饰器模式的区别?

答案

维度适配器模式装饰器模式
目的接口转换,解决不兼容问题增强功能,添加新行为
接口输入和输出接口不同装饰前后接口相同
使用时机对接已有代码/第三方库需要动态增加功能

Q2: SLF4J 的适配器设计?

答案

SLF4J 定义了统一的日志接口(Logger),通过不同的桥接包适配不同的日志实现:

  • slf4j-log4j12:SLF4J → Log4j
  • logback-classic:SLF4J → Logback
  • slf4j-jdk14:SLF4J → JUL

项目代码只面向 SLF4J 接口编程,切换日志实现只需换桥接包,不改业务代码。

相关链接