【设计模式】【结构型模式】适配器模式(Adpter)

简介: 一、入门 什么是适配器模式? 适配器模式是Java中常用的结构型设计模式,它的核心作用就像现实中的电源转换器一样---让原本不兼容的两个接口能够协同工作。 为什么要用适配器模式? 假设我们需要在电商系

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

一、入门

什么是适配器模式?

适配器模式是Java中常用的结构型设计模式,它的核心作用就像现实中的电源转换器一样---让原本不兼容的两个接口能够协同工作。

为什么要用适配器模式?

假设我们需要在电商系统中接入两种第三方支付:

  1. 支付宝支付:方法名为 aliPay(String orderId, BigDecimal amount)
  2. 微信支付:方法名为 wechatPay(int merchantId, String orderNo, double money)

痛点:两个支付接口方法名、参数类型、参数顺序完全不同,导致业务代码中支付逻辑混乱。

// 支付宝SDK(参数:订单ID + 金额)
class AliPaySDK {
   
    public boolean aliPay(String orderId, BigDecimal amount) {
   
        System.out.println("支付宝支付成功:" + orderId + " 金额:" + amount);
        return true;
    }
}

// 微信支付SDK(参数:商户ID + 订单号 + 金额)
class WechatPaySDK {
   
    public boolean wechatPay(int merchantId, String orderNo, double money) {
   
        System.out.println("微信支付成功:商户" + merchantId + " 订单:" + orderNo + " 金额:" + money);
        return true;
    }
}

如何实现适配器模式?

适配器模式(Adapter)包含以下主要角色

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

【案例】三方支付 - 改

image.png

目标接口UnifiedPayment类。当前系统业务所期待的接口,它可以是抽象类或接口。

interface UnifiedPayment {
   
    /**
     * 统一支付方法
     * @param unifiedOrder 包含商户ID、订单号、金额等
     */
    boolean pay(UnifiedOrder unifiedOrder);
}

// 统一订单参数对象
class UnifiedOrder {
   
    private int merchantId;
    private String orderId;
    private BigDecimal amount;

    // 构造方法、getters省略
}

适配器AliPayAdapter类和WechatPayAdapter
适配者AliPaySDK类和WechatPaySDK

// 支付宝适配器
class AliPayAdapter implements UnifiedPayment {
   
    private AliPaySDK aliPay = new AliPaySDK();

    @Override
    public boolean pay(UnifiedOrder order) {
   
        // 参数转换与适配逻辑
        return aliPay.aliPay(
            order.getOrderId(),      // 直接使用统一订单号
            order.getAmount()       // 金额类型匹配
        );
    }
}

// 微信支付适配器
class WechatPayAdapter implements UnifiedPayment {
   
    private WechatPaySDK wechatPay = new WechatPaySDK();

    @Override
    public boolean pay(UnifiedOrder order) {
   
        // 微信特殊处理逻辑
        String wechatOrderNo = "WX_" + order.getOrderId();

        return wechatPay.wechatPay(
            order.getMerchantId(),   // 从统一参数获取商户ID
            wechatOrderNo,           // 转换订单号格式
            order.getAmount().doubleValue() // BigDecimal转double
        );
    }
}

改造后业务层

public class PaymentService {
   
    private Map<PayType, UnifiedPayment> adapters = new HashMap<>();

    public PaymentService() {
   
        adapters.put(PayType.ALI_PAY, new AliPayAdapter());
        adapters.put(PayType.WECHAT_PAY, new WechatPayAdapter());
    }

    public boolean pay(PayType type, UnifiedOrder order) {
   
        return adapters.get(type).pay(order); // 统一调用
    }
}

⚠注意:适配器这层不做业务逻辑校验

适配器这层不做业务逻辑校验,如下所示

class WechatPayAdapter implements UnifiedPayment {
   
    // 错误!适配器不应包含业务判断
    public boolean pay(UnifiedOrder order) {
   
        if (order.amount > 10000) {
    // 业务规则不应在这里
            throw new Exception("超额限制"); 
        }
        // ...转换逻辑
    }
}

二、适配器模式在框架源码中的运用

Java I/O 的 InputStreamReader

InputStreamReader将字节流(InputStream)转换为字符流(Reader),解决字节流与字符流接口不兼容问题。

  • 目标接口:Reader
  • 适配器:InputStreamReader
  • 适配者:InputStream
public class InputStreamReader extends Reader {
   
    private final StreamDecoder sd; // 关键适配器

    public InputStreamReader(InputStream in) {
   
        this(in, Charset.defaultCharset());
    }

    // 通过StreamDecoder适配字节→字符
    public int read() throws IOException {
   
        return sd.read();
    }
}

Spring MVC 的 HandlerAdapter

Spring 要支持多种 Controller 类型(如 @ControllerHttpRequestHandlerServlet 等),但不同 Controller的请求处理方式不同。
目标接口HandlerAdapter接口

public interface HandlerAdapter {
   
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, 
                       HttpServletResponse response, 
                       Object handler) throws Exception;
}

适配器RequestMappingHandlerAdapter类和SimpleServletHandlerAdapter类。

// 具体适配器示例:处理注解式Controller
public class RequestMappingHandlerAdapter implements HandlerAdapter {
   
    public boolean supports(Object handler) {
   
        return (handler instanceof HandlerMethod);
    }

    public ModelAndView handle(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler) throws Exception {
   
        // 实际调用被注解的Controller方法
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        return invokeHandlerMethod(request, response, handlerMethod);
    }
}

// 另一个适配器:处理Servlet
public class SimpleServletHandlerAdapter implements HandlerAdapter {
   
    public boolean supports(Object handler) {
   
        return (handler instanceof Servlet);
    }

    public ModelAndView handle(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler) throws Exception {
   
        ((Servlet) handler).service(request, response);
        return null;
    }
}

适配者:我们用户实现的接口。

// 注解驱动的 Controller
@Controller
public class MyController {
   
    @RequestMapping("/hello")
    public String hello() {
   
        return "hello";
    }
}
// 基于接口的 Controller:
public class MyHttpRequestHandler implements HttpRequestHandler {
   
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
   
        // 处理请求
    }
}
// 传统的 Servlet
public class MyServlet extends HttpServlet {
   
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
   
        // 处理请求
    }
}

三、总结

适配器模式的优点

  1. 解耦性
    • 将客户端与具体实现分离,客户端只依赖目标接口,无需关心底层实现。
    • 例如:Spring MVC 的 DispatcherServlet 只依赖 HandlerAdapter 接口,不关心具体 Controller 的实现。
  2. 复用性
    • 可以复用现有的类或第三方库,而无需修改其源码。
    • 例如:通过 InputStreamReader 复用 InputStream 的功能。
  3. 扩展性
    • 新增适配器即可支持新的实现,符合开闭原则。
    • 例如:Spring MVC 新增一种 Controller 类型时,只需添加对应的 HandlerAdapter
  4. 透明性
    ○ 客户端无需感知适配器的存在,调用方式与普通接口一致。
    ○ 例如:使用 SLF4J 日志框架时,无需关心底层是Logback还是Log4j

适配器模式的缺点

  1. 增加复杂性
    • 引入适配器会增加类的数量,可能导致系统复杂度上升。
    • 例如:一个系统中有多种数据格式转换时,可能需要多个适配器。
  2. 性能开销
    • 适配器通常需要额外的逻辑(如数据转换),可能带来一定的性能损耗。
    • 例如:InputStreamReader 在字节到字符的转换过程中会有解码开销。
  3. 过度使用问题
    • 如果滥用适配器模式,可能导致系统层次过多,难以维护。
    • 例如:在简单的场景中,直接修改接口可能比引入适配器更合适。

适配器模式的适用场景

  1. 整合遗留代码
    • 场景:系统中存在老旧的模块或第三方库,无法直接修改其源码。
    • 示例:将老式的 XML 数据接口适配为新的 JSON 接口。
  2. 统一接口规范
    • 场景:需要将多个不同的实现统一为相同的接口。
    • 示例:Spring MVC 的 HandlerAdapter 统一处理多种 Controller 类型。
  3. 兼容不同版本
    • 场景:系统升级时,需要同时支持新旧版本的接口。
    • 示例:API 升级时,通过适配器兼容旧版客户端。
  4. 跨平台或跨系统集成
    • 场景:需要与外部系统对接,但接口规范不一致。
    • 示例:将微信支付的接口适配为统一的支付接口。
  5. 数据格式转换
    • 场景:需要将一种数据格式转换为另一种格式。
    • 示例:InputStreamReader 将字节流转换为字符流。
目录
相关文章
|
1月前
|
设计模式 存储 缓存
【设计模式】【结构型模式】享元模式(Flyweight)
一、入门 什么是享元模式? 享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来减少内存使用,特别适用于存在大量相似对象的情况。 它的核心思想是将对象的内在状态(不变
77 16
|
1月前
|
设计模式 Java 数据库连接
【设计模式】【结构型模式】代理模式(Proxy)
一、入门 什么是代理模式? 代理模式(Proxy Pattern)是一种结构型设计模式,允许你提供一个代理对象来控制对另一个对象的访问。 代理对象在客户端和目标对象之间起到中介作用,可以在不改变目标对
63 10
|
1月前
|
设计模式 Java 定位技术
【设计模式】【结构型模式】组合模式(Composite)
一、入门 什么是组合模式 组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组合模式使得客户端可以统一处理单个对象和组合对
66 10
|
1月前
|
设计模式 Java 数据库连接
【设计模式】【结构型模式】外观模式(Facde)
一、入门 什么是外观模式? 一种结构型设计模式,通过为子系统中的一组接口提供一个统一的高层接口(称为外观),来简化客户端与复杂子系统的交互过程。其本质是建立抽象层来隔离复杂度。 为什么要有外观模式?
68 9
|
1月前
|
关系型数据库 Java MySQL
【设计模式】【结构型模式】桥接模式(Bridge)
一、入门 什么是桥接模式? 桥接模式(Bridge Pattern)是一种结构型设计模式,核心思想是将抽象与实现分离,让它们可以独立变化。简单来说,它像一座“桥”连接了两个维度的变化,避免用继承导致代
130 10
|
1月前
|
设计模式 缓存 安全
【设计模式】【结构型模式】装饰者模式(Decorator)
一、入门 什么是装饰者模式? 装饰者模式(Decorator Pattern)是 Java 中常用的结构型设计模式,它能在不修改原有对象结构的前提下,动态地为对象添加额外的职责。 为什么要装饰者模式?
47 8
|
5月前
|
设计模式 Java 开发者
「全网最细 + 实战源码案例」设计模式——适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,通过引入适配器类将一个类的接口转换为客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够协同工作。适配器模式分为类适配器和对象适配器两种,前者通过多重继承实现,后者通过组合方式实现,更常用。该模式适用于遗留系统改造、接口转换和第三方库集成等场景,能提高代码复用性和灵活性,但也可能增加代码复杂性和性能开销。
126 28
|
6月前
|
设计模式 JSON 前端开发
前端必须掌握的设计模式——适配器模式
适配器模式是一种结构型设计模式,用于使接口不兼容的对象能够相互合作。通过在客户端和系统之间引入一个“中间层”适配器,将不同类型的输入数据转换为系统能处理的标准格式,减轻系统的负担,提高扩展性和可维护性。例如,MacBook的扩展坞将多种接口(如HDMI、USB)转换为Type-C接口,实现多接口兼容。
|
9月前
|
设计模式 Java 程序员
Java设计模式-适配器模式(8)
Java设计模式-适配器模式(8)
|
10月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)

热门文章

最新文章