中 基础
适配器模式#
一句话答案#
将一个类的接口转换为客户端期望的接口,使不兼容的类协作;Spring HandlerAdapter 适配不同类型 Controller。
核心要点
适配器模式将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作。
两种实现方式:
| 方式 | 实现 | 特点 |
|---|---|---|
| 类适配器 | 适配器继承被适配类 + 实现目标接口 | Java 单继承限制,不常用 |
| 对象适配器 | 适配器持有被适配对象的引用 + 实现目标接口 | 推荐,组合优于继承 |
// 目标接口
public interface Target {
void request();
}
// 被适配的类(旧接口)
public class Adaptee {
public void specificRequest() { /* 旧逻辑 */ }
}
// 对象适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest(); // 转发调用
}
}javaSpring MVC 中的 HandlerAdapter:
Spring MVC 支持多种类型的 Controller:
@Controller+@RequestMapping(注解式)- 实现
Controller接口 - 实现
HttpRequestHandler接口
这些 Handler 的调用方式各不相同。HandlerAdapter 作为适配器,将不同类型 Handler 的调用方式统一:
DispatcherServlet
│
▼ 调用统一接口 adapter.handle(request, response, handler)
HandlerAdapter(目标接口)
├── RequestMappingHandlerAdapter → 处理 @RequestMapping 注解的方法
├── SimpleControllerHandlerAdapter → 处理实现 Controller 接口的类
└── HttpRequestHandlerAdapter → 处理实现 HttpRequestHandler 的类plaintext核心流程:
DispatcherServlet根据请求找到 Handler(Controller 方法)- 遍历所有
HandlerAdapter,找到能处理该 Handler 的适配器(supports(handler)返回 true) - 调用适配器的
handle()方法,内部将请求转发给对应的 Handler
Java SDK 中的适配器:
Arrays.asList()—— 数组适配为 ListInputStreamReader—— 字节流适配为字符流Collections.enumeration()—— Collection 适配为 Enumeration
面试回答(2分钟版)
适配器模式的核心是将一个类的接口转换成客户端期望的另一个接口,让原本不兼容的类可以协作。就像电源转接头一样,把三脚插头适配成两孔插座。实现方式有两种:类适配器通过继承被适配类同时实现目标接口,但受 Java 单继承限制不常用;对象适配器通过组合持有被适配对象的引用,更灵活也是推荐方式。Spring MVC 中的 HandlerAdapter 就是适配器模式的经典应用——Spring MVC 支持多种 Controller 类型,有注解式的 @RequestMapping、实现 Controller 接口的、实现 HttpRequestHandler 的,它们的调用方式各不相同。HandlerAdapter 把这些不同类型的 Handler 统一适配成 DispatcherServlet 能识别的 handle() 接口。Java SDK 中也有很多例子,比如 Arrays.asList() 把数组适配为 List,InputStreamReader 把字节流适配为字符流。适配器模式在遗留系统集成的场景中特别有价值,不用改老代码就能对接新系统。
追问与易错
追问方向:
- “类适配器和对象适配器区别?”→ 类适配器通过继承被适配类 + 实现目标接口,受 Java 单继承限制且耦合度高;对象适配器通过组合持有被适配对象引用 + 实现目标接口,更灵活,推荐使用
- “Spring MVC 为什么需要 HandlerAdapter?”→ Spring MVC 支持多种 Handler 类型(@RequestMapping 注解式、Controller 接口、HttpRequestHandler 接口),调用方式各不同,HandlerAdapter 将它们统一适配为 DispatcherServlet 能调用的 handle() 接口
- “和门面区别?”→ 适配器是为了兼容两个已有接口做转换(解决不兼容问题);门面是为复杂子系统提供一个简化的统一入口(降低使用复杂度),目的不同
易错点:
- ❌ 适配器就是封装——核心是接口转换
- ❌ 不推荐用——遗留系统集成非常有用