当前位置: 首页 > 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.dtcms.com/a/295460.html

相关文章:

  • RustDesk 完整部署教程:支持 Web 管理后台和网页客户端远程,保姆级教学来了!
  • 【SpringAI实战】提示词工程实现哄哄模拟器
  • Mybatis_2
  • 5.1 神经元、神经网络的理解
  • AI大模型各类概念扫盲
  • 鸿蒙平台运行Lua脚本
  • easyexcel流式导出
  • 100元以下的儿童益智玩具推荐
  • 达梦数据库集群启停顺序全解析
  • GitHub开源项目Zerox:AI驱动的OCR革命
  • 5G-RAN与语义通信RAN
  • 社区资源媒体管理系统设计与实现
  • Spring Boot 遇上 MyBatis-Plus:高效开发的奇妙之旅
  • IO密集型、CPU密集型、负载、负载均衡
  • 250714脑电分析课题进展——基础知识扩展与论文阅读
  • java中如何返回一个可以执行返回操作(return action)的函数或对象
  • 商场导航软件的核心技术实现:3D+AI 如何解决用户搜索意图识别难题
  • 两台电脑连接交换机,使用其中一台电脑的网络上网(NAT转发)
  • Solo:基于 zkHE 的身份验证协议,构建 Web3 可信匿名身份层
  • 数字系统自动设计:从C++到门级网表
  • 在LLM中中 写好prompt 最快的方式
  • Prompt自优化框架核心信息及举例
  • 【自用】JavaSE--阶段测试
  • Java进阶3:Java集合框架、ArrayList、LinkedList、HashSet、HashMap和他们的迭代器
  • C++开发---奥比中光(Orbbec)的ob库
  • list 介绍 及 底层
  • esp32 挂载mpu6050实现加速度计
  • MiniCPM 学习部署实战 vlm
  • OSPF开放式最短路径优先
  • 【Git知识】Git 常用知识集合之基础--分支系统与 Tag 标签机制