当前位置: 首页 > news >正文

适配器模式——以springboot为例

什么是适配器模式?

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的对象能够相互合作。简单来说,适配器模式就像我们日常生活中的电源适配器,它能够连接两个原本不兼容的接口,使它们能够一起工作。

适配器模式的核心思想是:将一个类的接口转换成客户端所期望的另一个接口,使得原本因接口不兼容而无法一起工作的类能够协同工作。

适配器模式的结构

适配器模式主要包含以下角色:

  1. 目标接口(Target):目标接口,客户端所期望的接口
  2. 适配者(Adaptee):需要被适配的类或接口,但是与Target不兼容
  3. 适配器(Adapter):连接目标接口和适配者的中间件
  4. 用户(Client):需要适配器的对象

适配器模式有两种实现方式:

  • 类适配器:使用继承的方式
  • 对象适配器:使用组合的方式(更常用)

一个简单的适配器模式示例

假设我们有一个老系统中的 LegacyUser 类,但我们的新系统需要使用 User 接口。我们可以创建一个适配器来解决这个问题:

// 目标接口 (Target)
public interface User {String getName();String getEmail();String getPhone();
}// 适配者 (Adaptee) - 老系统中的类
public class LegacyUser {private String username;private String contact;private String telephone;// 构造函数、getter和setter省略public String getUsername() {return username;}public String getContact() {return contact;}public String getTelephone() {return telephone;}
}// 适配器 (Adapter)
public class LegacyUserAdapter implements User {private LegacyUser legacyUser;public LegacyUserAdapter(LegacyUser legacyUser) {this.legacyUser = legacyUser;}@Overridepublic String getName() {return legacyUser.getUsername();}@Overridepublic String getEmail() {return legacyUser.getContact();}@Overridepublic String getPhone() {return legacyUser.getTelephone();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建一个老系统的用户LegacyUser oldUser = new LegacyUser();oldUser.setUsername("张三");oldUser.setContact("zhangsan@example.com");oldUser.setTelephone("13800138000");// 使用适配器将老系统用户适配到新系统User adaptedUser = new LegacyUserAdapter(oldUser);// 现在可以使用新系统的接口了System.out.println("姓名: " + adaptedUser.getName());System.out.println("邮箱: " + adaptedUser.getEmail());System.out.println("电话: " + adaptedUser.getPhone());}
}

Spring Boot 中的适配器模式

Spring Boot 框架中大量使用了适配器模式,下面我们来看几个典型的例子:

1. Spring MVC 中的 HandlerAdapter

在 Spring MVC 中,DispatcherServlet 是前端控制器,负责将请求分发给不同的处理器(Handler)。但是这些处理器的类型可能各不相同(如 Controller、HttpRequestHandler 等),它们的接口也不一致。

为了统一处理这些不同类型的处理器,Spring MVC 使用了适配器模式,引入了 HandlerAdapter 接口:

// 目标接口
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;long getLastModified(HttpServletRequest request, Object handler);
}

Spring MVC 为不同类型的处理器提供了不同的适配器实现:

// 适配器实现示例 - 为 @RequestMapping 注解的控制器提供适配
public class RequestMappingHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return handler instanceof HandlerMethod;}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 处理请求的逻辑return handleInternal(request, response, (HandlerMethod) handler);}// 其他方法实现...
}

DispatcherServlet 的处理流程大致如下:

// DispatcherServlet 中的处理逻辑(简化版)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 找到处理请求的 handlerObject handler = getHandler(request);// 找到适合该 handler 的 HandlerAdapterHandlerAdapter ha = getHandlerAdapter(handler);// 使用适配器处理请求ModelAndView mv = ha.handle(request, response, handler);// 处理视图...
}// 查找合适的适配器
private HandlerAdapter getHandlerAdapter(Object handler) {for (HandlerAdapter ha : this.handlerAdapters) {if (ha.supports(handler)) {return ha;}}throw new ServletException("No adapter for handler [" + handler + "]");
}

通过这种方式,Spring MVC 可以支持多种类型的处理器,而 DispatcherServlet 不需要知道具体处理器的实现细节。

2. Spring Boot 中的 WebMvcConfigurer 适配器

在 Spring Boot 2.0 之前,我们通常通过继承 WebMvcConfigurerAdapter 来自定义 MVC 配置:

// Spring Boot 1.x 中的用法
public class WebConfig extends WebMvcConfigurerAdapter {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor());}
}

WebMvcConfigurerAdapter 就是一个适配器类,它实现了 WebMvcConfigurer 接口的所有方法(提供空实现),这样我们只需要重写需要的方法即可。

在 Java 8 之后,接口可以有默认方法,所以在 Spring Boot 2.0 中,WebMvcConfigurerAdapter 被废弃了,我们可以直接实现 WebMvcConfigurer 接口:

// Spring Boot 2.x 中的用法
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor());}
}

3. Spring Boot 中的 MessageConverter

Spring Boot 中的 HttpMessageConverter 也是适配器模式的一个很好的例子。它负责将 HTTP 请求体转换为 Java 对象,或将 Java 对象转换为 HTTP 响应体。

// 目标接口
public interface HttpMessageConverter<T> {boolean canRead(Class<?> clazz, MediaType mediaType);boolean canWrite(Class<?> clazz, MediaType mediaType);List<MediaType> getSupportedMediaTypes();T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}

Spring Boot 提供了多种 HttpMessageConverter 的实现,如 MappingJackson2HttpMessageConverter(处理 JSON)、MarshallingHttpMessageConverter(处理 XML)等。

实现一个自定义的 Spring Boot 适配器

让我们实现一个自定义的适配器,将第三方 API 的数据格式适配到我们的系统中:

假设我们有一个第三方天气 API,但它的数据格式与我们系统需要的格式不同:

// 第三方天气 API 提供的数据格式
public class ThirdPartyWeatherData {private String cityCode;private double temp;private int humidity;private String weatherCondition;// 构造函数、getter和setter省略
}// 我们系统中使用的天气数据格式
public interface WeatherInfo {String getCityName();double getTemperature();int getHumidity();String getCondition();boolean isRainy();
}// 适配器实现
@Service
public class WeatherAdapter implements WeatherInfo {private final ThirdPartyWeatherData thirdPartyData;private final CityService cityService; // 用于将城市代码转换为城市名称@Autowiredpublic WeatherAdapter(ThirdPartyWeatherService thirdPartyService, CityService cityService) {this.thirdPartyData = thirdPartyService.getWeatherData();this.cityService = cityService;}@Overridepublic String getCityName() {// 将城市代码转换为城市名称return cityService.getCityNameByCode(thirdPartyData.getCityCode());}@Overridepublic double getTemperature() {// 假设第三方API返回的是华氏度,我们需要转换为摄氏度return (thirdPartyData.getTemp() - 32) * 5 / 9;}@Overridepublic int getHumidity() {return thirdPartyData.getHumidity();}@Overridepublic String getCondition() {return thirdPartyData.getWeatherCondition();}@Overridepublic boolean isRainy() {// 根据天气状况判断是否下雨String condition = thirdPartyData.getWeatherCondition().toLowerCase();return condition.contains("rain") || condition.contains("drizzle");}
}// 控制器中使用适配器
@RestController
@RequestMapping("/weather")
public class WeatherController {private final WeatherInfo weatherInfo;@Autowiredpublic WeatherController(WeatherAdapter weatherAdapter) {this.weatherInfo = weatherAdapter;}@GetMapping("/current")public Map<String, Object> getCurrentWeather() {Map<String, Object> result = new HashMap<>();result.put("city", weatherInfo.getCityName());result.put("temperature", weatherInfo.getTemperature());result.put("humidity", weatherInfo.getHumidity());result.put("condition", weatherInfo.getCondition());result.put("isRainy", weatherInfo.isRainy());return result;}
}

适配器模式的优缺点

优点:

  1. 增加了类的透明性:通过适配器,客户端可以调用同一接口,无需关心底层实现
  2. 提高了类的复用性:适配器可以让原本不兼容的类一起工作
  3. 灵活性和扩展性好:可以在不修改原有代码的情况下,引入并使用新的组件

缺点:

  1. 增加了系统的复杂性:引入了新的类和接口
  2. 可能会导致代码可读性下降:如果过度使用适配器,可能会让系统变得难以理解

适配器模式的应用场景

  1. 需要使用一个已存在的类,但其接口不符合需求时
  2. 需要统一多个类的接口时
  3. 需要复用一些现有的类,但不能修改其源代码时
  4. 需要在新旧系统之间建立联系时

总结

适配器模式是一种非常实用的设计模式,它帮助我们解决接口不兼容的问题。在 Spring Boot 等框架中,适配器模式被广泛应用,使得框架能够灵活地支持各种不同的组件和实现。

http://www.lryc.cn/news/598302.html

相关文章:

  • RK3568笔记九十一:QT环境搭建
  • 【Java基础06】ArrayList
  • AudioLLM 开源项目了解学习
  • 构建企业级Docker日志驱动:将容器日志无缝发送到腾讯云CLS
  • 新mac电脑软件安装指南(前端开发用)
  • 2025年计算机网络与教育科学国际会议(ICCNES 2025)
  • IntelliJ IDEA中管理多版本Git子模块的完整指南
  • Elasticsearch安全审计日志设置与最佳实践
  • 从零构建:Jenkins与Kubernetes集成的完整指南
  • 福佑储能轴流风扇对储能安全的重要影响
  • 陪诊小程序系统开发:开启医疗陪护新时代
  • JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
  • 盲盒抽谷机小程序:二次元经济的“社交裂变引擎”如何引爆用户增长?
  • Apache 消息队列分布式架构与原理
  • 移动端自动化Appium框架
  • [数据结构]#7 哈希表
  • 2025年6月GESP(C++六级):学习小组
  • OpenMed 项目深度分析:推动医疗 NLP 领域的开源革命
  • GoLand 项目从 0 到 1:第二天 —— 数据库自动化
  • 综合实验(4)
  • 独家|百度副总裁尚国斌即将离职,此前统筹百度地图;行业搜索及智能体业务总经理谢天转岗IDG
  • Vue-23-通过flask接口提供的数据使用plotly.js绘图(二)
  • Unity 多人游戏框架学习系列九
  • 图机器学习(19)——金融数据分析
  • 2026第35届中国国际健康产业博览会:探寻大健康时代的未来!
  • KTH5791——3D 霍尔位置传感器--鼠标滚轮专用芯片
  • 【C语言进阶】动态内存管理的面试题||练习
  • Day 20:奇异值SVD分解
  • 第四章自定义编辑器窗口_创建and打开and自定义窗口(3/11)
  • vue3升级了哪些重要功能