面试知识库
基础

适配器模式#

一句话答案#

将一个类的接口转换为客户端期望的接口,使不兼容的类协作;Spring HandlerAdapter 适配不同类型 Controller。

核心要点

适配器模式将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作。

两种实现方式:

方式实现特点
类适配器适配器继承被适配类 + 实现目标接口Java 单继承限制,不常用
对象适配器适配器持有被适配对象的引用 + 实现目标接口推荐,组合优于继承

Spring 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

核心流程:

  1. DispatcherServlet 根据请求找到 Handler(Controller 方法)
  2. 遍历所有 HandlerAdapter,找到能处理该 Handler 的适配器(supports(handler) 返回 true)
  3. 调用适配器的 handle() 方法,内部将请求转发给对应的 Handler

Java SDK 中的适配器:

  • Arrays.asList() —— 数组适配为 List
  • InputStreamReader —— 字节流适配为字符流
  • 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() 接口
  • “和门面区别?”→ 适配器是为了兼容两个已有接口做转换(解决不兼容问题);门面是为复杂子系统提供一个简化的统一入口(降低使用复杂度),目的不同

易错点:

  • ❌ 适配器就是封装——核心是接口转换
  • ❌ 不推荐用——遗留系统集成非常有用