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

设计模式-适配器模式详解

适配器模式详解

1. 适配器模式简介

1.1 定义

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类能够相互合作。适配器模式通过创建一个包装类(适配器)来包装现有类,使其接口与客户端期望的接口兼容。

1.2 核心思想

  • 转换接口:将不兼容的接口转换为客户端期望的接口
  • 包装现有类:不修改原有类,通过包装的方式实现功能
  • 解耦:客户端与具体实现类解耦,只依赖抽象接口

1.3 模式结构

1.3.1 基本结构图
uses
implements
uses
Client
+main()
«interface»
Target
+request()
Adapter
-adaptee: Adaptee
+request()
Adaptee
+specificRequest()
1.3.2 时序图
ClientTargetAdapterAdapteerequest()request()specificRequest()responseresponseresponseClientTargetAdapterAdaptee
1.3.3 类适配器 vs 对象适配器对比
对象适配器 (Object Adapter)
类适配器 (Class Adapter)
继承
组合
Target Interface
Client
Adapter
Adaptee
Target Interface
Client
Adapter
Adaptee

2. 应用场景

2.1 典型场景

  1. 第三方库集成:集成不兼容的第三方库
  2. 遗留系统改造:改造老系统,保持接口兼容
  3. 数据格式转换:不同数据格式之间的转换
  4. API版本兼容:新老API版本之间的适配
  5. 数据库适配:不同数据库之间的操作适配

2.2 实际应用示例

2.2.1 支付系统适配器架构
支付系统适配器架构
PaymentService接口
支付客户端
PaymentAdapter
AlipayAdapter
WechatAdapter
UnionPayAdapter
支付宝SDK
微信支付SDK
银联SDK
2.2.2 日志框架适配器
日志适配器示例
Logger接口
应用代码
Log4jAdapter
SLF4JAdapter
JULAdapter
Log4j实现
SLF4J实现
JUL实现
2.2.3 常见应用场景
  • 支付系统:适配不同支付渠道(支付宝、微信、银联)
  • 日志框架:适配不同日志实现(Log4j、SLF4J、JUL)
  • 缓存系统:适配不同缓存实现(Redis、Memcached、本地缓存)
  • 消息队列:适配不同MQ实现(RabbitMQ、Kafka、ActiveMQ)

3. 重难点分析

3.1 设计难点

3.1.1 接口设计
// 目标接口设计要合理,不能过于复杂
public interface Target {void request();
}// 避免接口过于臃肿
public interface BadTarget {void method1();void method2();// ... 太多方法
}
3.1.2 适配器实现
// 类适配器:继承方式
public class ClassAdapter extends Adaptee implements Target {@Overridepublic void request() {specificRequest(); // 调用父类方法}
}// 对象适配器:组合方式(推荐)
public class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}

3.2 常见问题

3.2.1 过度使用
  • 问题:为每个不兼容的类都创建适配器
  • 解决:优先考虑重构,适配器应该是最后的选择
3.2.2 性能问题
  • 问题:适配器增加了一层调用,可能影响性能
  • 解决:在性能敏感场景下谨慎使用
3.2.3 维护成本
  • 问题:适配器过多导致维护困难
  • 解决:统一管理适配器,建立适配器注册机制

4. 在Spring中的应用

4.1 Spring MVC中的适配器模式

4.1.1 HandlerAdapter架构图
Spring MVC HandlerAdapter架构
HandlerMapping
DispatcherServlet
HandlerAdapter
ViewResolver
HandlerMethod
Controller
HttpRequestHandler
Servlet
RequestMappingHandlerAdapter
SimpleControllerHandlerAdapter
HttpRequestHandlerAdapter
SimpleServletHandlerAdapter
4.1.2 HandlerAdapter工作流程
客户端DispatcherServletHandlerMappingHandlerAdapter具体HandlerHTTP请求获取Handler返回Handler对象获取HandlerAdaptersupports(handler)返回适配器handle(request, response, handler)调用具体处理方法返回ModelAndView返回ModelAndView返回响应客户端DispatcherServletHandlerMappingHandlerAdapter具体Handler
4.1.3 HandlerAdapter
// Spring MVC中的HandlerAdapter接口
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}// 具体适配器实现
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 {// 处理@RequestMapping注解的Controller方法return handleInternal(request, response, (HandlerMethod) handler);}
}
4.1.3 HandlerAdapter适配器选择流程
返回true
返回false
DispatcherServlet收到请求
HandlerMapping获取Handler
遍历HandlerAdapter列表
调用supports方法
找到匹配的适配器
尝试下一个适配器
还有适配器吗?
抛出异常: 没有找到适配器
调用handle方法处理请求
返回ModelAndView
4.1.4 适配器链模式
// DispatcherServlet中的适配器选择逻辑
protected HandlerAdapter getHandlerAdapter(Object handler) {for (HandlerAdapter ha : this.handlerAdapters) {if (ha.supports(handler)) {return ha;}}throw new ServletException("No adapter for handler [" + handler + "]");
}

4.2 Spring Security中的适配器

4.2.1 AuthenticationProvider适配器
// 适配不同的认证提供者
public class DaoAuthenticationProvider implements AuthenticationProvider {private UserDetailsService userDetailsService;private PasswordEncoder passwordEncoder;@Overridepublic Authentication authenticate(Authentication authentication) {// 适配UserDetailsService和PasswordEncoderString username = authentication.getName();UserDetails user = userDetailsService.loadUserByUsername(username);// 密码验证逻辑return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());}
}

4.3 Spring Boot自动配置中的适配器

4.3.1 条件适配器
@Configuration
@ConditionalOnClass(RedisTemplate.class)
public class RedisAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {// 适配不同的Redis客户端实现RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);return template;}
}

5. 相关源码解读

5.1 Spring MVC HandlerAdapter源码分析

5.1.1 核心接口
// org.springframework.web.servlet.HandlerAdapter
public interface HandlerAdapter {// 判断是否支持该处理器boolean supports(Object handler);// 处理请求ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;// 获取最后修改时间long getLastModified(HttpServletRequest request, Object handler);
}
5.1.2 实现类分析
// RequestMappingHandlerAdapter - 处理@RequestMapping
public class RequestMappingHandlerAdapter extends WebContentGeneratorimplements HandlerAdapter, InitializingBean, BeanFactoryAware {@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);}
}// SimpleControllerHandlerAdapter - 处理Controller接口
public class SimpleControllerHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return (handler instanceof Controller);}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return ((Controller) handler).handleRequest(request, response);}
}

5.2 Spring Security AuthenticationProvider源码

5.2.1 认证提供者接口
// org.springframework.security.authentication.AuthenticationProvider
public interface AuthenticationProvider {// 执行认证Authentication authenticate(Authentication authentication) throws AuthenticationException;// 是否支持该认证类型boolean supports(Class<?> authentication);
}
5.2.2 具体实现分析
// DaoAuthenticationProvider - 基于数据库的认证
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {private UserDetailsService userDetailsService;private PasswordEncoder passwordEncoder;@Overrideprotected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {if (authentication.getCredentials() == null) {throw new BadCredentialsException("密码不能为空");}String presentedPassword = authentication.getCredentials().toString();if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {throw new BadCredentialsException("密码错误");}}@Overrideprotected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {return userDetailsService.loadUserByUsername(username);}
}

6. 面试高频点

6.1 知识点结构图

适配器模式面试要点
定义
基础概念
核心思想
两种实现方式
与其他模式区别
HandlerAdapter
Spring应用
AuthenticationProvider
AutoConfiguration
何时使用
设计问题
何时不使用
优缺点分析
性能考虑
支付系统
实际应用
日志框架
缓存系统
消息队列
Spring MVC源码
源码分析
Spring Security源码
自定义适配器

6.2 面试重点分布图

25%30%20%15%10%面试重点分布基础概念Spring应用设计问题实际应用源码分析

6.3 知识点关系图

核心知识点
适配器模式学习路径
实现方式
模式定义
应用场景
Spring集成
源码理解
Spring应用
基础概念
设计问题
源码分析
实际应用
面试准备

6.4 基础概念

  1. 什么是适配器模式?

    • 结构型设计模式,用于接口不兼容的类之间的协作
    • 通过包装现有类,使其接口与客户端期望的接口兼容
  2. 适配器模式的两种实现方式?

    • 类适配器:通过继承实现
    • 对象适配器:通过组合实现(推荐)
  3. 适配器模式与装饰器模式的区别?

    • 适配器:改变接口,使不兼容的接口能够协作
    • 装饰器:增强功能,不改变接口

6.5 设计问题

  1. 如何选择类适配器还是对象适配器?

    • 对象适配器更灵活,推荐使用
    • 类适配器在Java中受限于单继承
  2. 适配器模式有什么缺点?

    • 增加系统复杂性
    • 可能影响性能
    • 维护成本增加
  3. 什么时候不应该使用适配器模式?

    • 可以重构代码解决接口不兼容时
    • 性能要求极高的场景
    • 接口差异过大,适配成本过高

6.6 Spring相关

  1. Spring MVC中如何使用适配器模式?

    • HandlerAdapter接口统一处理不同类型的Controller
    • 支持多种Controller类型(@Controller、Controller接口等)
  2. Spring Security中的适配器应用?

    • AuthenticationProvider适配不同的认证方式
    • 支持多种认证提供者

6.7 实际应用

  1. 如何设计一个支付系统的适配器?
// 支付接口
public interface PaymentService {PaymentResult pay(PaymentRequest request);
}// 支付宝适配器
public class AlipayAdapter implements PaymentService {private AlipayService alipayService;@Overridepublic PaymentResult pay(PaymentRequest request) {// 转换请求格式AlipayRequest alipayRequest = convertToAlipayRequest(request);AlipayResponse response = alipayService.pay(alipayRequest);// 转换响应格式return convertToPaymentResult(response);}
}
  1. 如何设计一个日志适配器?
// 统一日志接口
public interface Logger {void info(String message);void error(String message, Throwable throwable);
}// Log4j适配器
public class Log4jAdapter implements Logger {private org.apache.log4j.Logger logger;public Log4jAdapter(Class<?> clazz) {this.logger = org.apache.log4j.Logger.getLogger(clazz);}@Overridepublic void info(String message) {logger.info(message);}@Overridepublic void error(String message, Throwable throwable) {logger.error(message, throwable);}
}

7. 学习途径

7.1 理论学习

  1. 设计模式经典书籍

    • 《设计模式:可复用面向对象软件的基础》(GoF)
    • 《Head First设计模式》
    • 《设计模式之美》(王争)
  2. 在线资源

    • GitHub上的设计模式实现示例
    • 设计模式相关的技术博客
    • 视频教程(B站、慕课网等)

7.2 实践学习

  1. 项目实践

    • 在现有项目中识别适配器模式的应用场景
    • 尝试重构现有代码,使用适配器模式
    • 设计新的适配器解决实际问题
  2. 源码阅读

    • Spring Framework源码
    • Spring Boot自动配置源码
    • 其他开源框架的适配器实现
  3. 练习项目

    • 实现一个多支付渠道的支付系统
    • 设计一个多数据源的ORM适配器
    • 创建一个多消息队列的消息适配器

7.3 进阶学习

  1. 相关模式

    • 装饰器模式
    • 外观模式
    • 桥接模式
  2. 框架应用

    • Spring Boot自动配置原理
    • MyBatis插件机制
    • Dubbo SPI机制
  3. 性能优化

    • 适配器模式的性能影响分析
    • 缓存机制在适配器中的应用
    • 异步适配器设计

7.4 学习建议

  1. 循序渐进:从基础概念到实际应用
  2. 理论结合实践:多写代码,多思考
  3. 源码学习:深入理解框架中的实现
  4. 项目驱动:在实际项目中应用所学知识
  5. 持续学习:关注新技术,学习新的应用场景

8. 总结

适配器模式是一种非常重要的结构型设计模式,在Spring框架中有着广泛的应用。通过适配器模式,我们可以:

  • 解决接口不兼容问题:让不兼容的类能够协作
  • 保持代码的灵活性:不修改原有代码,通过适配器扩展功能
  • 提高代码的可维护性:统一接口,降低耦合度

在学习和应用适配器模式时,要注重理论与实践的结合,多阅读优秀框架的源码,在实际项目中不断练习和总结。只有这样,才能真正掌握适配器模式的精髓,并在实际开发中灵活运用。


文章转载自:

http://5xLySxFV.bqdgr.cn
http://0pJ6zKeY.bqdgr.cn
http://a1jSQVty.bqdgr.cn
http://6YFCcEiv.bqdgr.cn
http://WN4n4QZf.bqdgr.cn
http://ny8DCBjW.bqdgr.cn
http://VPKjErmq.bqdgr.cn
http://KgqnM0xV.bqdgr.cn
http://71OzyCE5.bqdgr.cn
http://HpUJttOf.bqdgr.cn
http://vlK3u0gH.bqdgr.cn
http://698kkpvO.bqdgr.cn
http://29qTRskR.bqdgr.cn
http://XskXhzdF.bqdgr.cn
http://LwCwqI5N.bqdgr.cn
http://9RmZ7LHD.bqdgr.cn
http://NxydS7ZP.bqdgr.cn
http://77BM4k79.bqdgr.cn
http://3yKL7dAC.bqdgr.cn
http://dZYehlsn.bqdgr.cn
http://mH6j55Gd.bqdgr.cn
http://TzlPMPSS.bqdgr.cn
http://wa6GVGei.bqdgr.cn
http://EbA1sVAX.bqdgr.cn
http://oxvgaoBM.bqdgr.cn
http://03DMqcyb.bqdgr.cn
http://FQ3dZJBa.bqdgr.cn
http://mijq6lkL.bqdgr.cn
http://FoMbzhgq.bqdgr.cn
http://4KEEfRWd.bqdgr.cn
http://www.dtcms.com/a/383234.html

相关文章:

  • Java 分布式缓存实现:结合 RMI 与本地文件缓存
  • Ajax-day2(图书管理)-渲染列表
  • 在Excel和WPS表格中快速复制上一行内容
  • 11-复习java程序设计中学习的面向对象编程
  • 《云计算如何驱动企业数字化转型:关键技术与实践案例》
  • LSTM 深度解析:从门控机制到实际应用
  • FPGA学习篇——Verilog学习Led灯的实现
  • 【ARDUINO】Arduino Uno 获取 OV7576 数据并通过 ESP8266 发送到 TCP 客户端(待测试)
  • xtuoj 原根
  • JVM 核心知识全解析:从类加载到垃圾回收的深度认知
  • Cesium4--地形(OSGB到3DTiles)
  • NLP:Transformer之self-attention(特别分享3)
  • 07 常用损失函数
  • UDP Socket 进阶:从 Echo 到字典服务器,学会 “解耦” 网络与业务
  • 多语言编码Agent解决方案(4)-Eclipse插件实现
  • 深入理解线程模型
  • LMCache:KV缓存管理
  • 关于物联网的基础知识(三)——物联网技术架构:连接万物的智慧之道!连接未来的万物之网!
  • 《嵌入式硬件(十一):基于IMX6ULL的中断操作》
  • 【Pywinauto库】12.4 pywinauto.uia_element_info后端内部实施模块
  • 工程机械健康管理物联网系统:移动互联与多工况诊断的技术实现
  • python递归解压压缩文件方法
  • 深入 Spring MVC 返回值处理器
  • 黑马JavaWeb+AI笔记 Day05 Web后端基础(JDBC)
  • Open3D 射线投射(Ray Casting,Python)
  • RL【10-1】:Actor - Critic
  • 计算机视觉(opencv)实战二十一——基于 SIFT 和 FLANN 的指纹图像匹配与认证
  • 纯`css`固定标题并在滚动时为其添加动画
  • 金融科技:银行中的风险管理
  • 【办公类-113-01】20250914小2班生日手机备忘录提示、手机同屏到电脑UIBOT(双休日前移、节假日前移)