适配器模式(Adapter Pattern)是Java中最常用的结构型设计模式之一,核心目标是解决接口不兼容问题。下面从原理到实现进行全面解析:
一、模式本质
转换接口:将一个类的接口转换成客户端期望的另一个接口,使原本因接口不匹配而无法协作的类能一起工作
类比现实:电源转接头(将不同国家插头标准适配到本地插座)
二、三种实现方式对比
类型 | 实现机制 | 优缺点 | 适用场景 |
---|---|---|---|
类适配器 | 继承源类 + 实现目标接口 | ✅ 适配代码少 ❌ Java不支持多继承 | 源类与目标接口差异较小 |
对象适配器 | 聚合源类对象 + 实现目标接口 | ✅ 更灵活(组合优于继承) ✅ 支持多适配 | 实际开发中最常用 |
接口适配器 | 抽象类实现目标接口默认方法 | ✅ 避免实现所有方法 ❌ 需创建抽象类 | 目标接口方法过多时做简化 |
三、对象适配器详解(主流实现)
场景模拟
// 源接口:220V电源(现有但不符合需求) class AC220v {public int output220V() {return 220;} }// 目标接口:5V充电器(客户端需要的接口) interface DC5V {int output5V(); // 输出5V电压 }
适配器实现
public class PowerAdapter implements DC5V {private AC220v ac220v; // 聚合源对象public PowerAdapter(AC220v ac220v) {this.ac220v = ac220v;}@Overridepublic int output5V() {int srcVoltage = ac220v.output220V(); // 获取源电压int dstVoltage = srcVoltage; // 电压转换逻辑System.out.println("适配器工作:220V → 5V");return dstVoltage;} }
客户端调用
public class MobileClient {public static void main(String[] args) {AC220v srcPower = new AC220v(); // 现有电源DC5V adapter = new PowerAdapter(srcPower); // 创建适配器int output = adapter.output5V(); // 调用目标接口System.out.println("手机充电电压:" + output + "V");} }
四、类适配器实现(需多重继承,Java中不推荐)
// 通过继承源类实现(注意:Java单继承限制实际场景) public class PowerAdapter extends AC220v implements DC5V {@Overridepublic int output5V() {int srcVoltage = super.output220V(); // 直接调用父类方法return srcVoltage;} }
五、接口适配器(缺省适配器)
解决痛点:当目标接口方法过多,但客户端仅需部分方法时
// 目标接口(包含多个方法)
interface FileOperations {
void read();
void write();
void delete();
void copy();
}
// 抽象适配器(空实现所有方法)
abstract class DefaultFileAdapter implements FileOperations {
public void read() {} // 空实现
public void write() {} // 空实现
public void delete() {} // 空实现
public void copy() {} // 空实现
}
// 按需重写特定方法
class CustomFileReader extends DefaultFileAdapter {
@Override
public void read() {
System.out.println("仅实现读取功能");
}
}
六、工业级应用场
-
JDBC驱动
graph LR A[Java App] -->|JDBC标准接口| B(MySQL Adapter) B -->|转换SQL语法| C[MySQL数据库]同一套JDBC接口适配不同数据库(MySQL/Oracle/SQL Server)
-
Spring MVC注解适配
@Controller public class UserController {// 将HTTP请求适配到Java方法@GetMapping("/users")public List<User> getUsers() { ... } }
-
日志框架兼容
- SLF4J作为门面接口,通过适配器兼容Log4j、JUL等实现
-
旧系统改造
- 遗留系统接口 ← 适配器 → 新系统接口
七、与类似模式对比
模式 | 核心目的 | 关键区别 |
---|---|---|
适配器模式 | 接口转换(解决兼容性问题) | 关注已有接口的复用 |
装饰器模式 | 功能增强(不改变接口) | 保持接口一致,增加新职责 |
代理模式 | 访问控制(间接访问对象) | 控制对象访问,接口通常不变 |
八、最佳实践建议
- 优先选择对象适配器(组合优于继承,更符合开闭原则)
- 避免过度设计:仅在确实存在接口不兼容时使用
- 适配器命名规范:
源类名+Adapter
(如InputStreamReader
) - 注意性能损耗:多层适配可能增加调用链(尤其在I/O场景)
适配器模式本质是妥协方案,理想情况下应通过统一接口设计避免使用,但在集成第三方库、兼容旧系统等场景中不可或缺。