Spring + 设计模式 (九) 结构型 - 适配器模式

322 阅读4分钟

适配器模式

引言

适配器模式是一种结构型设计模式,旨在将一个类的接口转换为客户端期望的另一接口,使原本不兼容的类能够协同工作。它如同电源适配器,将不同标准的插头与插座连接,解决接口不匹配问题。适配器模式强调兼容性与复用性,特别适合整合遗留系统或第三方库,以最小改动实现无缝协作,赋予系统灵活性与优雅。

实际开发中的用途

适配器模式在实际开发中广泛应用于接口不兼容的场景,例如:

  • 遗留系统对接:新系统需调用旧接口时,适配器包装旧代码,适配新接口,避免重写。
  • 第三方库整合:外部库接口与项目需求不符,适配器提供统一调用方式,降低使用成本。
  • 多源数据处理:统一不同数据源的接口(如XML、JSON),简化客户端逻辑。

它通过解耦客户端与具体实现,增强扩展性,特别在企业级应用中,是连接新旧模块、提升可维护性的关键工具。

开发中的示例

设想一个日志系统,原有文件日志记录器与新需求中的数据库日志记录器接口不同。直接调用会导致代码混乱。通过适配器模式,可定义统一日志接口,创建文件和数据库适配器,分别封装各自逻辑。客户端通过统一接口记录日志,无需关心底层实现,代码简洁且易于扩展新日志方式(如云日志)。

Spring 源码中的应用

在 Spring 框架中,适配器模式在 HandlerAdapter 的实现中体现得淋漓尽致。HandlerAdapter 是 Spring MVC 的核心组件,负责将不同类型的控制器(如 @Controller、传统 Controller 接口)适配为 DispatcherServlet 能处理的统一接口,屏蔽底层差异。

以下是 Spring 源码片段(DispatcherServlet.java):

// Spring 框架中的 DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 省略部分代码...
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // 省略部分代码...
    ha.handle(request, response, mappedHandler.getHandler());
}

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler [" + handler + "]");
}

分析

  1. 适配器模式的体现

    • HandlerAdapter 接口定义了 supportshandle 方法,充当适配器接口。
    • 具体适配器(如 RequestMappingHandlerAdapterSimpleControllerHandlerAdapter)实现该接口,适配不同控制器类型。
    • DispatcherServlet 通过 getHandlerAdapter 动态选择适配器,调用 handle 执行控制器逻辑。
  2. 关键逻辑

    • getHandlerAdapter 遍历 handlerAdapters,找到支持当前控制器的适配器。
    • ha.handle 将请求适配到控制器执行逻辑,隐藏实现细节。
  3. 解耦与扩展性

    • 客户端(DispatcherServlet)与控制器实现解耦,支持新增控制器类型只需添加新适配器,符合开闭原则。
    • 适配器统一了请求处理流程,增强框架灵活性。
  4. 问题解决

    • 支持多种控制器(如注解式、函数式),无需修改核心逻辑。
    • 提升 Spring MVC 的兼容性,适配器成为请求处理的中枢。

这种设计使 HandlerAdapter 成为 Spring MVC 的关键组件,完美展现适配器模式的兼容与复用能力。

Java实现案例

// 日志服务接口
public interface Logger {
    void log(String message);
}

// 文件日志记录器(旧系统)
public class FileLogger {
    public void writeToFile(String msg) {
        System.out.println("写入文件日志: " + msg);
    }
}

// 数据库日志记录器(新系统)
public class DatabaseLogger {
    public void saveToDatabase(String data) {
        System.out.println("保存数据库日志: " + data);
    }
}

// 文件日志适配器
public class FileLoggerAdapter implements Logger {
    private FileLogger fileLogger;

    public FileLoggerAdapter(FileLogger fileLogger) {
        this.fileLogger = fileLogger;
    }

    @Override
    public void log(String message) {
        fileLogger.writeToFile(message);
    }
}

// 数据库日志适配器
public class DatabaseLoggerAdapter implements Logger {
    private DatabaseLogger databaseLogger;

    public DatabaseLoggerAdapter(DatabaseLogger databaseLogger) {
        this.databaseLogger = databaseLogger;
    }

    @Override
    public void log(String message) {
        databaseLogger.saveToDatabase(message);
    }
}

// 客户端代码
public class AdapterPatternDemo {
    public static void main(String[] args) {
        // 创建日志记录器
        FileLogger fileLogger = new FileLogger();
        DatabaseLogger databaseLogger = new DatabaseLogger();

        // 创建适配器
        Logger fileAdapter = new FileLoggerAdapter(fileLogger);
        Logger dbAdapter = new DatabaseLoggerAdapter(databaseLogger);

        // 使用统一接口记录日志
        fileAdapter.log("用户登录成功");
        dbAdapter.log("用户执行操作");
    }
}

案例说明

此案例模拟一个日志系统,FileLogger(旧系统)和 DatabaseLogger(新系统)接口不同。Logger 接口定义统一日志方法,FileLoggerAdapterDatabaseLoggerAdapter 分别适配两者,封装具体实现。客户端通过 Logger 接口调用,屏蔽底层差异。适配器模式解耦了客户端与日志实现,支持新增日志方式(如云日志)只需添加新适配器,体现了高扩展性和低耦合性。

运行代码将输出:

写入文件日志: 用户登录成功
保存数据库日志: 用户执行操作

总结

适配器模式如同一座“接口桥梁”,让不兼容的系统无缝衔接,赋予代码无限兼容性。在 Spring 中,HandlerAdapter 通过适配器模式动态适配控制器,展现了框架的优雅与灵活。实际开发中,适配器模式简化了遗留系统整合与第三方库使用,让复杂性在统一接口后消融。掌握适配器模式,不仅能写出兼容性强的代码,更能设计出如 Spring 般优雅的架构,以最小的改动迎接最大的变化。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢