适配器模式是结构型模式里最常用、也最容易理解的一个,平时对接第三方接口、统一日志框架时一直在用。这篇把它的三种变体(类适配器、对象适配器、接口适配器)理清楚,以及它和装饰器、代理这两个"长得像"的兄弟怎么区分。
一、解决什么问题
适配器模式解决的是**"两个接口不兼容,但要一起工作"**的问题。
最直观的类比是电源适配器:墙上是 220V 的插座,手机要的是 5V 直流电,插不进去——中间加个充电头(适配器),把 220V 转成 5V,两边就对上了。
代码里同样常见:
- 对接第三方:对方的接口是
queryData(),你自己的系统调用的是getList(),需要一个适配器转换 - 统一日志:SLF4J 就是典型的适配器——它定义统一的日志接口,适配 Log4j、Logback 等不同实现
- 兼容旧系统:新系统要调用老系统的接口,但老接口的签名对不上
一句话:适配器 = 接口的"翻译官",把一个接口转换成客户端期望的另一个接口。
二、三种适配器
v1 对象适配器(组合,最常用)
java
// 目标接口:客户端期望的
public interface Target {
void request();
}
// 被适配者:已有的、不兼容的类
public class Adaptee {
public void specificRequest() {
System.out.println("被适配者的方法");
}
}
// 对象适配器:持有被适配者,转调
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) { this.adaptee = adaptee; }
public void request() {
adaptee.specificRequest(); // 把 request 转成 specificRequest
}
}
// 客户端
Target target = new ObjectAdapter(new Adaptee());
target.request();优点:通过组合持有被适配者,一个适配器能适配"被适配者及其所有子类",灵活。最推荐。
v2 类适配器(继承)
java
// 类适配器:直接继承被适配者,同时实现目标接口
public class ClassAdapter extends Adaptee implements Target {
public void request() {
super.specificRequest(); // 直接调用继承来的方法
}
}缺点:Java 单继承,继承了 Adaptee 就不能再继承别的,灵活性差。能用对象适配器就别用类适配器。
v3 接口适配器(适配器模式变体)
当一个接口有很多方法,但我们只想用其中几个时,不想实现所有方法——用一个"空实现"的中间类兜底:
java
// 原接口:方法太多
public interface MouseListener {
void click();
void doubleClick();
void rightClick();
void hover();
}
// 接口适配器:空实现所有方法
public abstract class MouseAdapter implements MouseListener {
public void click() {}
public void doubleClick() {}
public void rightClick() {}
public void hover() {}
}
// 使用方:只重写自己关心的方法
MouseListener listener = new MouseAdapter() {
public void click() { System.out.println("点击了"); }
};这就是"接口适配器/缺省适配器"——用一个空实现类,让使用方只重写关心的方法。
三、实际应用
- SLF4J:统一日志门面,
slf4j-api定义接口,slf4j-log4j12/logback-classic是适配器,把 SLF4J 接口转到具体日志实现 - JDBC 驱动:
Driver把统一的 JDBC 接口适配到各家数据库的私有协议 - 旧系统对接:老接口
getData()包装成新系统要的fetchList()
小结
- 适配器解决"接口不兼容",是接口的"翻译官"
- 三种:对象适配器(组合,推荐)、类适配器(继承,受单继承限制)、接口适配器(空实现兜底,只重写关心的方法)
- 典型:SLF4J 统一日志、JDBC 驱动、第三方对接
- 与装饰器/代理的区别:适配器是"接口转换"(两个不同接口),装饰器是"功能增强"(同一接口),代理是"访问控制"(同一接口)
想区分"同一接口下的增强与控制",接着看《装饰器模式》和《代理模式》(文章整理中)。
