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

适配器模式详解

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 {
    @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架构图
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 {
    @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适配器选择流程
返回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;
  
    @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 知识点结构图

适配器模式面试要点
定义
基础概念
核心思想
两种实现方式
与其他模式区别
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;
  
    @Override
    public 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);
    }
  
    @Override
    public void info(String message) {
        logger.info(message);
    }
  
    @Override
    public 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框架中有着广泛的应用。通过适配器模式,我们可以:

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

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值