设计模式-适配器模式详解
适配器模式详解
1. 适配器模式简介
1.1 定义
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类能够相互合作。适配器模式通过创建一个包装类(适配器)来包装现有类,使其接口与客户端期望的接口兼容。
1.2 核心思想
- 转换接口:将不兼容的接口转换为客户端期望的接口
- 包装现有类:不修改原有类,通过包装的方式实现功能
- 解耦:客户端与具体实现类解耦,只依赖抽象接口
1.3 模式结构
1.3.1 基本结构图
1.3.2 时序图
1.3.3 类适配器 vs 对象适配器对比
2. 应用场景
2.1 典型场景
- 第三方库集成:集成不兼容的第三方库
- 遗留系统改造:改造老系统,保持接口兼容
- 数据格式转换:不同数据格式之间的转换
- API版本兼容:新老API版本之间的适配
- 数据库适配:不同数据库之间的操作适配
2.2 实际应用示例
2.2.1 支付系统适配器架构
2.2.2 日志框架适配器
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架构图
4.1.2 HandlerAdapter工作流程
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适配器选择流程
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 知识点结构图
6.2 面试重点分布图
6.3 知识点关系图
6.4 基础概念
-
什么是适配器模式?
- 结构型设计模式,用于接口不兼容的类之间的协作
- 通过包装现有类,使其接口与客户端期望的接口兼容
-
适配器模式的两种实现方式?
- 类适配器:通过继承实现
- 对象适配器:通过组合实现(推荐)
-
适配器模式与装饰器模式的区别?
- 适配器:改变接口,使不兼容的接口能够协作
- 装饰器:增强功能,不改变接口
6.5 设计问题
-
如何选择类适配器还是对象适配器?
- 对象适配器更灵活,推荐使用
- 类适配器在Java中受限于单继承
-
适配器模式有什么缺点?
- 增加系统复杂性
- 可能影响性能
- 维护成本增加
-
什么时候不应该使用适配器模式?
- 可以重构代码解决接口不兼容时
- 性能要求极高的场景
- 接口差异过大,适配成本过高
6.6 Spring相关
-
Spring MVC中如何使用适配器模式?
- HandlerAdapter接口统一处理不同类型的Controller
- 支持多种Controller类型(@Controller、Controller接口等)
-
Spring Security中的适配器应用?
- AuthenticationProvider适配不同的认证方式
- 支持多种认证提供者
6.7 实际应用
- 如何设计一个支付系统的适配器?
// 支付接口
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);}
}
- 如何设计一个日志适配器?
// 统一日志接口
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 理论学习
-
设计模式经典书籍
- 《设计模式:可复用面向对象软件的基础》(GoF)
- 《Head First设计模式》
- 《设计模式之美》(王争)
-
在线资源
- GitHub上的设计模式实现示例
- 设计模式相关的技术博客
- 视频教程(B站、慕课网等)
7.2 实践学习
-
项目实践
- 在现有项目中识别适配器模式的应用场景
- 尝试重构现有代码,使用适配器模式
- 设计新的适配器解决实际问题
-
源码阅读
- Spring Framework源码
- Spring Boot自动配置源码
- 其他开源框架的适配器实现
-
练习项目
- 实现一个多支付渠道的支付系统
- 设计一个多数据源的ORM适配器
- 创建一个多消息队列的消息适配器
7.3 进阶学习
-
相关模式
- 装饰器模式
- 外观模式
- 桥接模式
-
框架应用
- Spring Boot自动配置原理
- MyBatis插件机制
- Dubbo SPI机制
-
性能优化
- 适配器模式的性能影响分析
- 缓存机制在适配器中的应用
- 异步适配器设计
7.4 学习建议
- 循序渐进:从基础概念到实际应用
- 理论结合实践:多写代码,多思考
- 源码学习:深入理解框架中的实现
- 项目驱动:在实际项目中应用所学知识
- 持续学习:关注新技术,学习新的应用场景
8. 总结
适配器模式是一种非常重要的结构型设计模式,在Spring框架中有着广泛的应用。通过适配器模式,我们可以:
- 解决接口不兼容问题:让不兼容的类能够协作
- 保持代码的灵活性:不修改原有代码,通过适配器扩展功能
- 提高代码的可维护性:统一接口,降低耦合度
在学习和应用适配器模式时,要注重理论与实践的结合,多阅读优秀框架的源码,在实际项目中不断练习和总结。只有这样,才能真正掌握适配器模式的精髓,并在实际开发中灵活运用。