适配器模式详解
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 {
@Override
public void request() {
specificRequest(); // 调用父类方法
}
}
// 对象适配器:组合方式(推荐)
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public 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 {
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerMethod;
}
@Override
public 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;
@Override
public Authentication authenticate(Authentication authentication) {
// 适配UserDetailsService和PasswordEncoder
String 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
@ConditionalOnMissingBean
public 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 WebContentGenerator
implements HandlerAdapter, InitializingBean, BeanFactoryAware {
@Override
public boolean supports(Object handler) {
return (handler instanceof HandlerMethod);
}
@Override
public ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
}
// SimpleControllerHandlerAdapter - 处理Controller接口
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
public 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;
@Override
protected 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("密码错误");
}
}
@Override
protected 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;
@Override
public 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);
}
@Override
public void info(String message) {
logger.info(message);
}
@Override
public 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框架中有着广泛的应用。通过适配器模式,我们可以:
- 解决接口不兼容问题:让不兼容的类能够协作
- 保持代码的灵活性:不修改原有代码,通过适配器扩展功能
- 提高代码的可维护性:统一接口,降低耦合度
在学习和应用适配器模式时,要注重理论与实践的结合,多阅读优秀框架的源码,在实际项目中不断练习和总结。只有这样,才能真正掌握适配器模式的精髓,并在实际开发中灵活运用。
931

被折叠的 条评论
为什么被折叠?



